29
29
import org .springframework .beans .factory .BeanFactory ;
30
30
import org .springframework .beans .factory .BeanFactoryAware ;
31
31
import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
32
+ import org .springframework .beans .factory .config .BeanDefinition ;
32
33
import org .springframework .beans .factory .config .ConfigurableBeanFactory ;
33
34
import org .springframework .context .ApplicationEvent ;
34
35
import org .springframework .context .ApplicationListener ;
@@ -70,7 +71,7 @@ public abstract class AbstractApplicationEventMulticaster
70
71
private ClassLoader beanClassLoader ;
71
72
72
73
@ Nullable
73
- private BeanFactory beanFactory ;
74
+ private ConfigurableBeanFactory beanFactory ;
74
75
75
76
private Object retrievalMutex = this .defaultRetriever ;
76
77
@@ -82,17 +83,17 @@ public void setBeanClassLoader(ClassLoader classLoader) {
82
83
83
84
@ Override
84
85
public void setBeanFactory (BeanFactory beanFactory ) {
85
- this .beanFactory = beanFactory ;
86
- if (beanFactory instanceof ConfigurableBeanFactory ) {
87
- ConfigurableBeanFactory cbf = (ConfigurableBeanFactory ) beanFactory ;
88
- if (this .beanClassLoader == null ) {
89
- this .beanClassLoader = cbf .getBeanClassLoader ();
90
- }
91
- this .retrievalMutex = cbf .getSingletonMutex ();
86
+ if (!(beanFactory instanceof ConfigurableBeanFactory )) {
87
+ throw new IllegalStateException ("Not running in a ConfigurableBeanFactory: " + beanFactory );
88
+ }
89
+ this .beanFactory = (ConfigurableBeanFactory ) beanFactory ;
90
+ if (this .beanClassLoader == null ) {
91
+ this .beanClassLoader = this .beanFactory .getBeanClassLoader ();
92
92
}
93
+ this .retrievalMutex = this .beanFactory .getSingletonMutex ();
93
94
}
94
95
95
- private BeanFactory getBeanFactory () {
96
+ private ConfigurableBeanFactory getBeanFactory () {
96
97
if (this .beanFactory == null ) {
97
98
throw new IllegalStateException ("ApplicationEventMulticaster cannot retrieve listener beans " +
98
99
"because it is not associated with a BeanFactory" );
@@ -221,6 +222,9 @@ private Collection<ApplicationListener<?>> retrieveApplicationListeners(
221
222
listeners = new LinkedHashSet <>(this .defaultRetriever .applicationListeners );
222
223
listenerBeans = new LinkedHashSet <>(this .defaultRetriever .applicationListenerBeans );
223
224
}
225
+
226
+ // Add programmatically registered listeners, including ones coming
227
+ // from ApplicationListenerDetector (singleton beans and inner beans).
224
228
for (ApplicationListener <?> listener : listeners ) {
225
229
if (supportsEvent (listener , eventType , sourceType )) {
226
230
if (retriever != null ) {
@@ -229,12 +233,14 @@ private Collection<ApplicationListener<?>> retrieveApplicationListeners(
229
233
allListeners .add (listener );
230
234
}
231
235
}
236
+
237
+ // Add listeners by bean name, potentially overlapping with programmatically
238
+ // registered listeners above - but here potentially with additional metadata.
232
239
if (!listenerBeans .isEmpty ()) {
233
- BeanFactory beanFactory = getBeanFactory ();
240
+ ConfigurableBeanFactory beanFactory = getBeanFactory ();
234
241
for (String listenerBeanName : listenerBeans ) {
235
242
try {
236
- Class <?> listenerType = beanFactory .getType (listenerBeanName );
237
- if (listenerType == null || supportsEvent (listenerType , eventType )) {
243
+ if (supportsEvent (beanFactory , listenerBeanName , eventType )) {
238
244
ApplicationListener <?> listener =
239
245
beanFactory .getBean (listenerBeanName , ApplicationListener .class );
240
246
if (!allListeners .contains (listener ) && supportsEvent (listener , eventType , sourceType )) {
@@ -249,13 +255,24 @@ private Collection<ApplicationListener<?>> retrieveApplicationListeners(
249
255
allListeners .add (listener );
250
256
}
251
257
}
258
+ else {
259
+ // Remove non-matching listeners that originally came from
260
+ // ApplicationListenerDetector, possibly ruled out by additional
261
+ // BeanDefinition metadata (e.g. factory method generics) above.
262
+ Object listener = beanFactory .getSingleton (listenerBeanName );
263
+ if (retriever != null ) {
264
+ retriever .applicationListeners .remove (listener );
265
+ }
266
+ allListeners .remove (listener );
267
+ }
252
268
}
253
269
catch (NoSuchBeanDefinitionException ex ) {
254
270
// Singleton listener instance (without backing bean definition) disappeared -
255
271
// probably in the middle of the destruction phase
256
272
}
257
273
}
258
274
}
275
+
259
276
AnnotationAwareOrderComparator .sort (allListeners );
260
277
if (retriever != null && retriever .applicationListenerBeans .isEmpty ()) {
261
278
retriever .applicationListeners .clear ();
@@ -264,6 +281,42 @@ private Collection<ApplicationListener<?>> retrieveApplicationListeners(
264
281
return allListeners ;
265
282
}
266
283
284
+ /**
285
+ * Filter a bean-defined listener early through checking its generically declared
286
+ * event type before trying to instantiate it.
287
+ * <p>If this method returns {@code true} for a given listener as a first pass,
288
+ * the listener instance will get retrieved and fully evaluated through a
289
+ * {@link #supportsEvent(ApplicationListener, ResolvableType, Class)} call afterwards.
290
+ * @param beanFactory the BeanFactory that contains the listener beans
291
+ * @param listenerBeanName the name of the bean in the BeanFactory
292
+ * @param eventType the event type to check
293
+ * @return whether the given listener should be included in the candidates
294
+ * for the given event type
295
+ * @see #supportsEvent(Class, ResolvableType)
296
+ * @see #supportsEvent(ApplicationListener, ResolvableType, Class)
297
+ */
298
+ private boolean supportsEvent (
299
+ ConfigurableBeanFactory beanFactory , String listenerBeanName , ResolvableType eventType ) {
300
+
301
+ Class <?> listenerType = beanFactory .getType (listenerBeanName );
302
+ if (listenerType == null || GenericApplicationListener .class .isAssignableFrom (listenerType ) ||
303
+ SmartApplicationListener .class .isAssignableFrom (listenerType )) {
304
+ return true ;
305
+ }
306
+ if (!supportsEvent (listenerType , eventType )) {
307
+ return false ;
308
+ }
309
+ try {
310
+ BeanDefinition bd = beanFactory .getMergedBeanDefinition (listenerBeanName );
311
+ ResolvableType genericEventType = bd .getResolvableType ().as (ApplicationListener .class ).getGeneric ();
312
+ return (genericEventType == ResolvableType .NONE || genericEventType .isAssignableFrom (eventType ));
313
+ }
314
+ catch (NoSuchBeanDefinitionException ex ) {
315
+ // Ignore - no need to check resolvable type for manually registered singleton
316
+ return true ;
317
+ }
318
+ }
319
+
267
320
/**
268
321
* Filter a listener early through checking its generically declared event
269
322
* type before trying to instantiate it.
@@ -276,10 +329,6 @@ private Collection<ApplicationListener<?>> retrieveApplicationListeners(
276
329
* for the given event type
277
330
*/
278
331
protected boolean supportsEvent (Class <?> listenerType , ResolvableType eventType ) {
279
- if (GenericApplicationListener .class .isAssignableFrom (listenerType ) ||
280
- SmartApplicationListener .class .isAssignableFrom (listenerType )) {
281
- return true ;
282
- }
283
332
ResolvableType declaredEventType = GenericApplicationListenerAdapter .resolveDeclaredEventType (listenerType );
284
333
return (declaredEventType == null || declaredEventType .isAssignableFrom (eventType ));
285
334
}
0 commit comments