diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/SingletonBeanRegistry.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/SingletonBeanRegistry.java index 79d0234c37d..e2188050f17 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/SingletonBeanRegistry.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/SingletonBeanRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 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. @@ -122,4 +122,11 @@ public interface SingletonBeanRegistry { */ int getSingletonCount(); + /** + * Return the singleton mutex used by this registry (for external collaborators). + * @return the mutex object (never {@code null}) + * @since 4.2 + */ + Object getSingletonMutex(); + } 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 e1790d5bf5d..2077a101bdb 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 2d857d49c0c..cf1ed74539d 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 @@ -67,10 +67,38 @@ public abstract class AbstractApplicationEventMulticaster private BeanFactory beanFactory; + private Object retrievalMutex = this.defaultRetriever; + + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.beanClassLoader = classLoader; + } + + @Override + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + if (beanFactory instanceof ConfigurableBeanFactory) { + ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory; + if (this.beanClassLoader == null) { + this.beanClassLoader = cbf.getBeanClassLoader(); + } + this.retrievalMutex = cbf.getSingletonMutex(); + } + } + + private BeanFactory getBeanFactory() { + if (this.beanFactory == null) { + throw new IllegalStateException("ApplicationEventMulticaster cannot retrieve listener beans " + + "because it is not associated with a BeanFactory"); + } + return this.beanFactory; + } + @Override public void addApplicationListener(ApplicationListener listener) { - synchronized (this.defaultRetriever) { + synchronized (this.retrievalMutex) { this.defaultRetriever.applicationListeners.add(listener); this.retrieverCache.clear(); } @@ -78,7 +106,7 @@ public abstract class AbstractApplicationEventMulticaster @Override public void addApplicationListenerBean(String listenerBeanName) { - synchronized (this.defaultRetriever) { + synchronized (this.retrievalMutex) { this.defaultRetriever.applicationListenerBeans.add(listenerBeanName); this.retrieverCache.clear(); } @@ -86,7 +114,7 @@ public abstract class AbstractApplicationEventMulticaster @Override public void removeApplicationListener(ApplicationListener listener) { - synchronized (this.defaultRetriever) { + synchronized (this.retrievalMutex) { this.defaultRetriever.applicationListeners.remove(listener); this.retrieverCache.clear(); } @@ -94,7 +122,7 @@ public abstract class AbstractApplicationEventMulticaster @Override public void removeApplicationListenerBean(String listenerBeanName) { - synchronized (this.defaultRetriever) { + synchronized (this.retrievalMutex) { this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName); this.retrieverCache.clear(); } @@ -102,34 +130,13 @@ public abstract class AbstractApplicationEventMulticaster @Override public void removeAllListeners() { - synchronized (this.defaultRetriever) { + synchronized (this.retrievalMutex) { this.defaultRetriever.applicationListeners.clear(); this.defaultRetriever.applicationListenerBeans.clear(); this.retrieverCache.clear(); } } - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; - } - - @Override - public void setBeanFactory(BeanFactory beanFactory) { - this.beanFactory = beanFactory; - if (this.beanClassLoader == null && beanFactory instanceof ConfigurableBeanFactory) { - this.beanClassLoader = ((ConfigurableBeanFactory) beanFactory).getBeanClassLoader(); - } - } - - private BeanFactory getBeanFactory() { - if (this.beanFactory == null) { - throw new IllegalStateException("ApplicationEventMulticaster cannot retrieve listener beans " + - "because it is not associated with a BeanFactory"); - } - return this.beanFactory; - } - /** * Return a Collection containing all ApplicationListeners. @@ -137,7 +144,7 @@ public abstract class AbstractApplicationEventMulticaster * @see org.springframework.context.ApplicationListener */ protected Collection> getApplicationListeners() { - synchronized (this.defaultRetriever) { + synchronized (this.retrievalMutex) { return this.defaultRetriever.getApplicationListeners(); } } @@ -168,39 +175,38 @@ 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, eventType, sourceType, retriever); + retrieveApplicationListeners(eventType, sourceType, retriever); this.retrieverCache.put(cacheKey, retriever); return listeners; } } else { // No ListenerRetriever caching -> no synchronization necessary - return retrieveApplicationListeners(event, eventType, sourceType, null); + return retrieveApplicationListeners(eventType, sourceType, null); } } /** * Actually retrieve the application listeners for the given event and source type. - * @param event the application event * @param eventType the event type * @param sourceType the event source type * @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes) * @return the pre-filtered list of application listeners for the given event and source type */ private Collection> retrieveApplicationListeners( - ApplicationEvent event, ResolvableType eventType, Class sourceType, ListenerRetriever retriever) { + ResolvableType eventType, Class sourceType, ListenerRetriever retriever) { 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); } @@ -270,9 +276,7 @@ public abstract class AbstractApplicationEventMulticaster * @return whether the given listener should be included in the candidates * for the given event type */ - protected boolean supportsEvent(ApplicationListener listener, - ResolvableType eventType, Class sourceType) { - + protected boolean supportsEvent(ApplicationListener listener, ResolvableType eventType, Class sourceType) { GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ? (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener)); return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));