AbstractApplicationEventMulticaster filters listeners against their type first, avoiding eager retrieval of listener instances for non-matching events
Issue: SPR-11501
This commit is contained in:
parent
fa44224430
commit
cb41f42791
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -162,10 +162,14 @@ public abstract class AbstractApplicationEventMulticaster implements Application
|
|||
BeanFactory beanFactory = getBeanFactory();
|
||||
for (String listenerBeanName : listenerBeans) {
|
||||
try {
|
||||
ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
|
||||
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
|
||||
retriever.applicationListenerBeans.add(listenerBeanName);
|
||||
allListeners.add(listener);
|
||||
Class<?> listenerType = beanFactory.getType(listenerBeanName);
|
||||
if (listenerType == null || supportsEvent(listenerType, event)) {
|
||||
ApplicationListener<?> listener =
|
||||
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
|
||||
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
|
||||
retriever.applicationListenerBeans.add(listenerBeanName);
|
||||
allListeners.add(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
|
@ -180,6 +184,25 @@ public abstract class AbstractApplicationEventMulticaster implements Application
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a listener early through checking its generically declared event
|
||||
* type before trying to instantiate it.
|
||||
* <p>If this method returns {@code true} for a given listener as a first pass,
|
||||
* the listener instance will get retrieved and fully evaluated through a
|
||||
* {@link #supportsEvent(ApplicationListener, Class, Class)} call afterwards.
|
||||
* @param listenerType the listener's type as determined by the BeanFactory
|
||||
* @param event the event to check
|
||||
* @return whether the given listener should be included in the candidates
|
||||
* for the given event type
|
||||
*/
|
||||
protected boolean supportsEvent(Class<?> listenerType, ApplicationEvent event) {
|
||||
if (SmartApplicationListener.class.isAssignableFrom(listenerType)) {
|
||||
return true;
|
||||
}
|
||||
Class<?> declaredEventType = GenericApplicationListenerAdapter.resolveDeclaredEventType(listenerType);
|
||||
return (declaredEventType == null || declaredEventType.isInstance(event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given listener supports the given event.
|
||||
* <p>The default implementation detects the {@link SmartApplicationListener}
|
||||
|
@ -189,8 +212,8 @@ public abstract class AbstractApplicationEventMulticaster implements Application
|
|||
* @param listener the target listener to check
|
||||
* @param eventType the event type to check against
|
||||
* @param sourceType the source type to check against
|
||||
* @return whether the given listener should be included in the
|
||||
* candidates for the given event type
|
||||
* @return whether the given listener should be included in the candidates
|
||||
* for the given event type
|
||||
*/
|
||||
protected boolean supportsEvent(ApplicationListener<?> listener,
|
||||
Class<? extends ApplicationEvent> eventType, Class<?> sourceType) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -54,14 +54,14 @@ public class GenericApplicationListenerAdapter implements SmartApplicationListen
|
|||
|
||||
@Override
|
||||
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
|
||||
Class<?> typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
|
||||
if (typeArg == null || typeArg.equals(ApplicationEvent.class)) {
|
||||
Class<?> declaredEventType = resolveDeclaredEventType(this.delegate.getClass());
|
||||
if (declaredEventType == null || declaredEventType.equals(ApplicationEvent.class)) {
|
||||
Class<?> targetClass = AopUtils.getTargetClass(this.delegate);
|
||||
if (targetClass != this.delegate.getClass()) {
|
||||
typeArg = GenericTypeResolver.resolveTypeArgument(targetClass, ApplicationListener.class);
|
||||
declaredEventType = resolveDeclaredEventType(targetClass);
|
||||
}
|
||||
}
|
||||
return (typeArg == null || typeArg.isAssignableFrom(eventType));
|
||||
return (declaredEventType == null || declaredEventType.isAssignableFrom(eventType));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,4 +74,9 @@ public class GenericApplicationListenerAdapter implements SmartApplicationListen
|
|||
return (this.delegate instanceof Ordered ? ((Ordered) this.delegate).getOrder() : Ordered.LOWEST_PRECEDENCE);
|
||||
}
|
||||
|
||||
|
||||
static Class<?> resolveDeclaredEventType(Class<?> listenerType) {
|
||||
return GenericTypeResolver.resolveTypeArgument(listenerType, ApplicationListener.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -110,14 +110,18 @@ public class ApplicationContextEventTests {
|
|||
context.registerBeanDefinition("listener1", new RootBeanDefinition(MyOrderedListener1.class));
|
||||
RootBeanDefinition listener2 = new RootBeanDefinition(MyOrderedListener2.class);
|
||||
listener2.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference("listener1"));
|
||||
listener2.setLazyInit(true);
|
||||
context.registerBeanDefinition("listener2", listener2);
|
||||
context.refresh();
|
||||
assertFalse(context.getDefaultListableBeanFactory().containsSingleton("listener2"));
|
||||
|
||||
MyOrderedListener1 listener1 = context.getBean("listener1", MyOrderedListener1.class);
|
||||
MyEvent event1 = new MyEvent(context);
|
||||
MyOtherEvent event1 = new MyOtherEvent(context);
|
||||
context.publishEvent(event1);
|
||||
MyOtherEvent event2 = new MyOtherEvent(context);
|
||||
assertFalse(context.getDefaultListableBeanFactory().containsSingleton("listener2"));
|
||||
MyEvent event2 = new MyEvent(context);
|
||||
context.publishEvent(event2);
|
||||
assertTrue(context.getDefaultListableBeanFactory().containsSingleton("listener2"));
|
||||
MyEvent event3 = new MyEvent(context);
|
||||
context.publishEvent(event3);
|
||||
MyOtherEvent event4 = new MyOtherEvent(context);
|
||||
|
|
Loading…
Reference in New Issue