Skip to content

Commit ad71c6a

Browse files
committed
AbstractApplicationEventMulticaster populates ListenerRetriever cache in fully synchronized fashion
Issue: SPR-12545 (cherry picked from commit 61a6bc0)
1 parent b30843a commit ad71c6a

File tree

1 file changed

+62
-37
lines changed

1 file changed

+62
-37
lines changed

spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java

+62-37
Original file line numberDiff line numberDiff line change
@@ -149,57 +149,82 @@ protected Collection<ApplicationListener<?>> getApplicationListeners() {
149149
* @see org.springframework.context.ApplicationListener
150150
*/
151151
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event) {
152-
Class<? extends ApplicationEvent> eventType = event.getClass();
153152
Object source = event.getSource();
154153
Class<?> sourceType = (source != null ? source.getClass() : null);
155-
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
154+
ListenerCacheKey cacheKey = new ListenerCacheKey(event.getClass(), sourceType);
155+
156+
// Quick check for existing entry on ConcurrentHashMap...
156157
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
157158
if (retriever != null) {
158159
return retriever.getApplicationListeners();
159160
}
160-
else {
161-
retriever = new ListenerRetriever(true);
162-
LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>();
163-
Set<ApplicationListener<?>> listeners;
164-
Set<String> listenerBeans;
161+
162+
if (this.beanClassLoader == null ||
163+
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
164+
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
165+
// Fully synchronized building and caching of a ListenerRetriever
165166
synchronized (this.defaultRetriever) {
166-
listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners);
167-
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
168-
}
169-
for (ApplicationListener<?> listener : listeners) {
170-
if (supportsEvent(listener, eventType, sourceType)) {
171-
retriever.applicationListeners.add(listener);
172-
allListeners.add(listener);
167+
retriever = this.retrieverCache.get(cacheKey);
168+
if (retriever != null) {
169+
return retriever.getApplicationListeners();
173170
}
171+
retriever = new ListenerRetriever(true);
172+
Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(event, sourceType, retriever);
173+
this.retrieverCache.put(cacheKey, retriever);
174+
return listeners;
174175
}
175-
if (!listenerBeans.isEmpty()) {
176-
BeanFactory beanFactory = getBeanFactory();
177-
for (String listenerBeanName : listenerBeans) {
178-
try {
179-
Class<?> listenerType = beanFactory.getType(listenerBeanName);
180-
if (listenerType == null || supportsEvent(listenerType, event)) {
181-
ApplicationListener<?> listener =
182-
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
183-
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
184-
retriever.applicationListenerBeans.add(listenerBeanName);
185-
allListeners.add(listener);
186-
}
176+
}
177+
else {
178+
// No ListenerRetriever caching -> no synchronization necessary
179+
return retrieveApplicationListeners(event, sourceType, null);
180+
}
181+
}
182+
183+
/**
184+
* Actually retrieve the application listeners for the given event and source type.
185+
* @param event the application event
186+
* @param sourceType the event source type
187+
* @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes)
188+
* @return the pre-filtered list of application listeners for the given event and source type
189+
*/
190+
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
191+
ApplicationEvent event, Class<?> sourceType, ListenerRetriever retriever) {
192+
193+
LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>();
194+
Set<ApplicationListener<?>> listeners;
195+
Set<String> listenerBeans;
196+
synchronized (this.defaultRetriever) {
197+
listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners);
198+
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
199+
}
200+
for (ApplicationListener<?> listener : listeners) {
201+
if (supportsEvent(listener, event.getClass(), sourceType)) {
202+
retriever.applicationListeners.add(listener);
203+
allListeners.add(listener);
204+
}
205+
}
206+
if (!listenerBeans.isEmpty()) {
207+
BeanFactory beanFactory = getBeanFactory();
208+
for (String listenerBeanName : listenerBeans) {
209+
try {
210+
Class<?> listenerType = beanFactory.getType(listenerBeanName);
211+
if (listenerType == null || supportsEvent(listenerType, event)) {
212+
ApplicationListener<?> listener =
213+
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
214+
if (!allListeners.contains(listener) && supportsEvent(listener, event.getClass(), sourceType)) {
215+
retriever.applicationListenerBeans.add(listenerBeanName);
216+
allListeners.add(listener);
187217
}
188218
}
189-
catch (NoSuchBeanDefinitionException ex) {
190-
// Singleton listener instance (without backing bean definition) disappeared -
191-
// probably in the middle of the destruction phase
192-
}
219+
}
220+
catch (NoSuchBeanDefinitionException ex) {
221+
// Singleton listener instance (without backing bean definition) disappeared -
222+
// probably in the middle of the destruction phase
193223
}
194224
}
195-
OrderComparator.sort(allListeners);
196-
if (this.beanClassLoader == null ||
197-
(ClassUtils.isCacheSafe(eventType, this.beanClassLoader) &&
198-
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
199-
this.retrieverCache.put(cacheKey, retriever);
200-
}
201-
return allListeners;
202225
}
226+
OrderComparator.sort(allListeners);
227+
return allListeners;
203228
}
204229

205230
/**

0 commit comments

Comments
 (0)