diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java index e1790d5bf5..2077a101bd 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -607,13 +607,13 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements } /** - * Expose the singleton mutex to subclasses. + * Exposes the singleton mutex to subclasses and external collaborators. *

Subclasses should synchronize on the given Object if they perform * any sort of extended singleton creation phase. In particular, subclasses * should not have their own mutexes involved in singleton creation, * to avoid the potential for deadlocks in lazy-init situations. */ - protected final Object getSingletonMutex() { + public final Object getSingletonMutex() { return this.singletonObjects; } diff --git a/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java b/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java index 850e4df4cf..05c2ed71b4 100644 --- a/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java +++ b/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.beans.factory.support.AbstractBeanFactory; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.core.OrderComparator; @@ -65,47 +66,8 @@ public abstract class AbstractApplicationEventMulticaster private BeanFactory beanFactory; + private Object retrievalMutex = this.defaultRetriever; - @Override - public void addApplicationListener(ApplicationListener listener) { - synchronized (this.defaultRetriever) { - this.defaultRetriever.applicationListeners.add(listener); - this.retrieverCache.clear(); - } - } - - @Override - public void addApplicationListenerBean(String listenerBeanName) { - synchronized (this.defaultRetriever) { - this.defaultRetriever.applicationListenerBeans.add(listenerBeanName); - this.retrieverCache.clear(); - } - } - - @Override - public void removeApplicationListener(ApplicationListener listener) { - synchronized (this.defaultRetriever) { - this.defaultRetriever.applicationListeners.remove(listener); - this.retrieverCache.clear(); - } - } - - @Override - public void removeApplicationListenerBean(String listenerBeanName) { - synchronized (this.defaultRetriever) { - this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName); - this.retrieverCache.clear(); - } - } - - @Override - public void removeAllListeners() { - synchronized (this.defaultRetriever) { - this.defaultRetriever.applicationListeners.clear(); - this.defaultRetriever.applicationListenerBeans.clear(); - this.retrieverCache.clear(); - } - } @Override public void setBeanClassLoader(ClassLoader classLoader) { @@ -118,6 +80,9 @@ public abstract class AbstractApplicationEventMulticaster if (this.beanClassLoader == null && beanFactory instanceof ConfigurableBeanFactory) { this.beanClassLoader = ((ConfigurableBeanFactory) beanFactory).getBeanClassLoader(); } + if (beanFactory instanceof AbstractBeanFactory) { + this.retrievalMutex = ((AbstractBeanFactory) beanFactory).getSingletonMutex(); + } } private BeanFactory getBeanFactory() { @@ -129,13 +94,55 @@ public abstract class AbstractApplicationEventMulticaster } + @Override + public void addApplicationListener(ApplicationListener listener) { + synchronized (this.retrievalMutex) { + this.defaultRetriever.applicationListeners.add(listener); + this.retrieverCache.clear(); + } + } + + @Override + public void addApplicationListenerBean(String listenerBeanName) { + synchronized (this.retrievalMutex) { + this.defaultRetriever.applicationListenerBeans.add(listenerBeanName); + this.retrieverCache.clear(); + } + } + + @Override + public void removeApplicationListener(ApplicationListener listener) { + synchronized (this.retrievalMutex) { + this.defaultRetriever.applicationListeners.remove(listener); + this.retrieverCache.clear(); + } + } + + @Override + public void removeApplicationListenerBean(String listenerBeanName) { + synchronized (this.retrievalMutex) { + this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName); + this.retrieverCache.clear(); + } + } + + @Override + public void removeAllListeners() { + synchronized (this.retrievalMutex) { + this.defaultRetriever.applicationListeners.clear(); + this.defaultRetriever.applicationListenerBeans.clear(); + this.retrieverCache.clear(); + } + } + + /** * Return a Collection containing all ApplicationListeners. * @return a Collection of ApplicationListeners * @see org.springframework.context.ApplicationListener */ protected Collection> getApplicationListeners() { - synchronized (this.defaultRetriever) { + synchronized (this.retrievalMutex) { return this.defaultRetriever.getApplicationListeners(); } } @@ -163,13 +170,14 @@ public abstract class AbstractApplicationEventMulticaster (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { // Fully synchronized building and caching of a ListenerRetriever - synchronized (this.defaultRetriever) { + synchronized (this.retrievalMutex) { retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } retriever = new ListenerRetriever(true); - Collection> listeners = retrieveApplicationListeners(event, sourceType, retriever); + Collection> listeners = + retrieveApplicationListeners(event, sourceType, retriever); this.retrieverCache.put(cacheKey, retriever); return listeners; } @@ -193,7 +201,7 @@ public abstract class AbstractApplicationEventMulticaster LinkedList> allListeners = new LinkedList>(); Set> listeners; Set listenerBeans; - synchronized (this.defaultRetriever) { + synchronized (this.retrievalMutex) { listeners = new LinkedHashSet>(this.defaultRetriever.applicationListeners); listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans); }