@@ -153,53 +153,79 @@ protected Collection<ApplicationListener<?>> getApplicationListeners(Application
153
153
Object source = event .getSource ();
154
154
Class <?> sourceType = (source != null ? source .getClass () : null );
155
155
ListenerCacheKey cacheKey = new ListenerCacheKey (eventType , sourceType );
156
+
157
+ // Quick check for existing entry on ConcurrentHashMap...
156
158
ListenerRetriever retriever = this .retrieverCache .get (cacheKey );
157
159
if (retriever != null ) {
158
160
return retriever .getApplicationListeners ();
159
161
}
160
- else {
161
- retriever = new ListenerRetriever ( true );
162
- LinkedList < ApplicationListener <?>> allListeners = new LinkedList < ApplicationListener <?>>();
163
- Set < ApplicationListener <?>> listeners ;
164
- Set < String > listenerBeans ;
162
+
163
+ if ( this . beanClassLoader == null ||
164
+ ( ClassUtils . isCacheSafe ( eventType , this . beanClassLoader ) &&
165
+ ( sourceType == null || ClassUtils . isCacheSafe ( sourceType , this . beanClassLoader )))) {
166
+ // Fully synchronized building and caching of a ListenerRetriever
165
167
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 );
168
+ retriever = this .retrieverCache .get (cacheKey );
169
+ if (retriever != null ) {
170
+ return retriever .getApplicationListeners ();
173
171
}
172
+ retriever = new ListenerRetriever (true );
173
+ Collection <ApplicationListener <?>> listeners = retrieveApplicationListeners (event , sourceType , retriever );
174
+ this .retrieverCache .put (cacheKey , retriever );
175
+ return listeners ;
174
176
}
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
- }
177
+ }
178
+ else {
179
+ // No ListenerRetriever caching -> no synchronization necessary
180
+ return retrieveApplicationListeners (event , sourceType , null );
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Actually retrieve the application listeners for the given event and source type.
186
+ * @param event the application event
187
+ * @param sourceType the event source type
188
+ * @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes)
189
+ * @return the pre-filtered list of application listeners for the given event and source type
190
+ */
191
+ private Collection <ApplicationListener <?>> retrieveApplicationListeners (
192
+ ApplicationEvent event , Class <?> sourceType , ListenerRetriever retriever ) {
193
+
194
+ LinkedList <ApplicationListener <?>> allListeners = new LinkedList <ApplicationListener <?>>();
195
+ Set <ApplicationListener <?>> listeners ;
196
+ Set <String > listenerBeans ;
197
+ synchronized (this .defaultRetriever ) {
198
+ listeners = new LinkedHashSet <ApplicationListener <?>>(this .defaultRetriever .applicationListeners );
199
+ listenerBeans = new LinkedHashSet <String >(this .defaultRetriever .applicationListenerBeans );
200
+ }
201
+ for (ApplicationListener <?> listener : listeners ) {
202
+ if (supportsEvent (listener , event .getClass (), sourceType )) {
203
+ retriever .applicationListeners .add (listener );
204
+ allListeners .add (listener );
205
+ }
206
+ }
207
+ if (!listenerBeans .isEmpty ()) {
208
+ BeanFactory beanFactory = getBeanFactory ();
209
+ for (String listenerBeanName : listenerBeans ) {
210
+ try {
211
+ Class <?> listenerType = beanFactory .getType (listenerBeanName );
212
+ if (listenerType == null || supportsEvent (listenerType , event )) {
213
+ ApplicationListener <?> listener =
214
+ beanFactory .getBean (listenerBeanName , ApplicationListener .class );
215
+ if (!allListeners .contains (listener ) && supportsEvent (listener , event .getClass (), sourceType )) {
216
+ retriever .applicationListenerBeans .add (listenerBeanName );
217
+ allListeners .add (listener );
187
218
}
188
219
}
189
- catch ( NoSuchBeanDefinitionException ex ) {
190
- // Singleton listener instance (without backing bean definition) disappeared -
191
- // probably in the middle of the destruction phase
192
- }
220
+ }
221
+ catch ( NoSuchBeanDefinitionException ex ) {
222
+ // Singleton listener instance (without backing bean definition) disappeared -
223
+ // probably in the middle of the destruction phase
193
224
}
194
225
}
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 ;
202
226
}
227
+ OrderComparator .sort (allListeners );
228
+ return allListeners ;
203
229
}
204
230
205
231
/**
0 commit comments