@@ -153,53 +153,79 @@ protected Collection<ApplicationListener<?>> getApplicationListeners(Application
153153 Object source = event .getSource ();
154154 Class <?> sourceType = (source != null ? source .getClass () : null );
155155 ListenerCacheKey cacheKey = new ListenerCacheKey (eventType , sourceType );
156+
157+ // Quick check for existing entry on ConcurrentHashMap...
156158 ListenerRetriever retriever = this .retrieverCache .get (cacheKey );
157159 if (retriever != null ) {
158160 return retriever .getApplicationListeners ();
159161 }
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
165167 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 ();
173171 }
172+ retriever = new ListenerRetriever (true );
173+ Collection <ApplicationListener <?>> listeners = retrieveApplicationListeners (event , sourceType , retriever );
174+ this .retrieverCache .put (cacheKey , retriever );
175+ return listeners ;
174176 }
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 );
187218 }
188219 }
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
193224 }
194225 }
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 ;
202226 }
227+ OrderComparator .sort (allListeners );
228+ return allListeners ;
203229 }
204230
205231 /**
0 commit comments