@@ -149,57 +149,82 @@ protected Collection<ApplicationListener<?>> getApplicationListeners() {
149
149
* @see org.springframework.context.ApplicationListener
150
150
*/
151
151
protected Collection <ApplicationListener <?>> getApplicationListeners (ApplicationEvent event ) {
152
- Class <? extends ApplicationEvent > eventType = event .getClass ();
153
152
Object source = event .getSource ();
154
153
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...
156
157
ListenerRetriever retriever = this .retrieverCache .get (cacheKey );
157
158
if (retriever != null ) {
158
159
return retriever .getApplicationListeners ();
159
160
}
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
165
166
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 ();
173
170
}
171
+ retriever = new ListenerRetriever (true );
172
+ Collection <ApplicationListener <?>> listeners = retrieveApplicationListeners (event , sourceType , retriever );
173
+ this .retrieverCache .put (cacheKey , retriever );
174
+ return listeners ;
174
175
}
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 );
187
217
}
188
218
}
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
193
223
}
194
224
}
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
225
}
226
+ OrderComparator .sort (allListeners );
227
+ return allListeners ;
203
228
}
204
229
205
230
/**
0 commit comments