|
|
@ -67,10 +67,38 @@ public abstract class AbstractApplicationEventMulticaster |
|
|
|
|
|
|
|
|
|
|
|
private BeanFactory beanFactory; |
|
|
|
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 |
|
|
|
@Override |
|
|
|
public void addApplicationListener(ApplicationListener<?> listener) { |
|
|
|
public void addApplicationListener(ApplicationListener<?> listener) { |
|
|
|
synchronized (this.defaultRetriever) { |
|
|
|
synchronized (this.retrievalMutex) { |
|
|
|
this.defaultRetriever.applicationListeners.add(listener); |
|
|
|
this.defaultRetriever.applicationListeners.add(listener); |
|
|
|
this.retrieverCache.clear(); |
|
|
|
this.retrieverCache.clear(); |
|
|
|
} |
|
|
|
} |
|
|
@ -78,7 +106,7 @@ public abstract class AbstractApplicationEventMulticaster |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void addApplicationListenerBean(String listenerBeanName) { |
|
|
|
public void addApplicationListenerBean(String listenerBeanName) { |
|
|
|
synchronized (this.defaultRetriever) { |
|
|
|
synchronized (this.retrievalMutex) { |
|
|
|
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName); |
|
|
|
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName); |
|
|
|
this.retrieverCache.clear(); |
|
|
|
this.retrieverCache.clear(); |
|
|
|
} |
|
|
|
} |
|
|
@ -86,7 +114,7 @@ public abstract class AbstractApplicationEventMulticaster |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void removeApplicationListener(ApplicationListener<?> listener) { |
|
|
|
public void removeApplicationListener(ApplicationListener<?> listener) { |
|
|
|
synchronized (this.defaultRetriever) { |
|
|
|
synchronized (this.retrievalMutex) { |
|
|
|
this.defaultRetriever.applicationListeners.remove(listener); |
|
|
|
this.defaultRetriever.applicationListeners.remove(listener); |
|
|
|
this.retrieverCache.clear(); |
|
|
|
this.retrieverCache.clear(); |
|
|
|
} |
|
|
|
} |
|
|
@ -94,7 +122,7 @@ public abstract class AbstractApplicationEventMulticaster |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void removeApplicationListenerBean(String listenerBeanName) { |
|
|
|
public void removeApplicationListenerBean(String listenerBeanName) { |
|
|
|
synchronized (this.defaultRetriever) { |
|
|
|
synchronized (this.retrievalMutex) { |
|
|
|
this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName); |
|
|
|
this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName); |
|
|
|
this.retrieverCache.clear(); |
|
|
|
this.retrieverCache.clear(); |
|
|
|
} |
|
|
|
} |
|
|
@ -102,34 +130,13 @@ public abstract class AbstractApplicationEventMulticaster |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void removeAllListeners() { |
|
|
|
public void removeAllListeners() { |
|
|
|
synchronized (this.defaultRetriever) { |
|
|
|
synchronized (this.retrievalMutex) { |
|
|
|
this.defaultRetriever.applicationListeners.clear(); |
|
|
|
this.defaultRetriever.applicationListeners.clear(); |
|
|
|
this.defaultRetriever.applicationListenerBeans.clear(); |
|
|
|
this.defaultRetriever.applicationListenerBeans.clear(); |
|
|
|
this.retrieverCache.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. |
|
|
|
* Return a Collection containing all ApplicationListeners. |
|
|
@ -137,7 +144,7 @@ public abstract class AbstractApplicationEventMulticaster |
|
|
|
* @see org.springframework.context.ApplicationListener |
|
|
|
* @see org.springframework.context.ApplicationListener |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
protected Collection<ApplicationListener<?>> getApplicationListeners() { |
|
|
|
protected Collection<ApplicationListener<?>> getApplicationListeners() { |
|
|
|
synchronized (this.defaultRetriever) { |
|
|
|
synchronized (this.retrievalMutex) { |
|
|
|
return this.defaultRetriever.getApplicationListeners(); |
|
|
|
return this.defaultRetriever.getApplicationListeners(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -168,39 +175,38 @@ public abstract class AbstractApplicationEventMulticaster |
|
|
|
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && |
|
|
|
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && |
|
|
|
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { |
|
|
|
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { |
|
|
|
// Fully synchronized building and caching of a ListenerRetriever
|
|
|
|
// Fully synchronized building and caching of a ListenerRetriever
|
|
|
|
synchronized (this.defaultRetriever) { |
|
|
|
synchronized (this.retrievalMutex) { |
|
|
|
retriever = this.retrieverCache.get(cacheKey); |
|
|
|
retriever = this.retrieverCache.get(cacheKey); |
|
|
|
if (retriever != null) { |
|
|
|
if (retriever != null) { |
|
|
|
return retriever.getApplicationListeners(); |
|
|
|
return retriever.getApplicationListeners(); |
|
|
|
} |
|
|
|
} |
|
|
|
retriever = new ListenerRetriever(true); |
|
|
|
retriever = new ListenerRetriever(true); |
|
|
|
Collection<ApplicationListener<?>> listeners = |
|
|
|
Collection<ApplicationListener<?>> listeners = |
|
|
|
retrieveApplicationListeners(event, eventType, sourceType, retriever); |
|
|
|
retrieveApplicationListeners(eventType, sourceType, retriever); |
|
|
|
this.retrieverCache.put(cacheKey, retriever); |
|
|
|
this.retrieverCache.put(cacheKey, retriever); |
|
|
|
return listeners; |
|
|
|
return listeners; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
// No ListenerRetriever caching -> no synchronization necessary
|
|
|
|
// 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. |
|
|
|
* Actually retrieve the application listeners for the given event and source type. |
|
|
|
* @param event the application event |
|
|
|
|
|
|
|
* @param eventType the event type |
|
|
|
* @param eventType the event type |
|
|
|
* @param sourceType the event source type |
|
|
|
* @param sourceType the event source type |
|
|
|
* @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes) |
|
|
|
* @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 |
|
|
|
* @return the pre-filtered list of application listeners for the given event and source type |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private Collection<ApplicationListener<?>> retrieveApplicationListeners( |
|
|
|
private Collection<ApplicationListener<?>> retrieveApplicationListeners( |
|
|
|
ApplicationEvent event, ResolvableType eventType, Class<?> sourceType, ListenerRetriever retriever) { |
|
|
|
ResolvableType eventType, Class<?> sourceType, ListenerRetriever retriever) { |
|
|
|
|
|
|
|
|
|
|
|
LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>(); |
|
|
|
LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>(); |
|
|
|
Set<ApplicationListener<?>> listeners; |
|
|
|
Set<ApplicationListener<?>> listeners; |
|
|
|
Set<String> listenerBeans; |
|
|
|
Set<String> listenerBeans; |
|
|
|
synchronized (this.defaultRetriever) { |
|
|
|
synchronized (this.retrievalMutex) { |
|
|
|
listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners); |
|
|
|
listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners); |
|
|
|
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans); |
|
|
|
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans); |
|
|
|
} |
|
|
|
} |
|
|
@ -270,9 +276,7 @@ public abstract class AbstractApplicationEventMulticaster |
|
|
|
* @return whether the given listener should be included in the candidates |
|
|
|
* @return whether the given listener should be included in the candidates |
|
|
|
* for the given event type |
|
|
|
* for the given event type |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
protected boolean supportsEvent(ApplicationListener<?> listener, |
|
|
|
protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, Class<?> sourceType) { |
|
|
|
ResolvableType eventType, Class<?> sourceType) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ? |
|
|
|
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ? |
|
|
|
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener)); |
|
|
|
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener)); |
|
|
|
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType)); |
|
|
|
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType)); |
|
|
|