ApplicationListeners will reliably get invoked through their proxy (if any)
This commit is contained in:
parent
ce6f14bd8b
commit
4d09809f17
|
|
@ -27,6 +27,7 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
|
@ -42,6 +43,7 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
|||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.support.ResourceEditorRegistrar;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
|
@ -708,6 +710,8 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
// Finally, re-register all internal BeanPostProcessors.
|
||||
OrderComparator.sort(internalPostProcessors);
|
||||
registerBeanPostProcessors(beanFactory, internalPostProcessors);
|
||||
|
||||
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1288,4 +1292,46 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* BeanPostProcessor that detects beans which implement the ApplicationListener interface.
|
||||
* This catches beans that can't reliably be detected by getBeanNamesForType.
|
||||
*/
|
||||
private class ApplicationListenerDetector implements MergedBeanDefinitionPostProcessor {
|
||||
|
||||
private final Map<String, Boolean> singletonNames = new ConcurrentHashMap<String, Boolean>();
|
||||
|
||||
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {
|
||||
if (beanDefinition.isSingleton()) {
|
||||
this.singletonNames.put(beanName, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
if (bean instanceof ApplicationListener) {
|
||||
// potentially not detected as a listener by getBeanNamesForType retrieval
|
||||
Boolean flag = this.singletonNames.get(beanName);
|
||||
if (Boolean.TRUE.equals(flag)) {
|
||||
// singleton bean (top-level or inner): register on the fly
|
||||
addApplicationListener((ApplicationListener) bean);
|
||||
}
|
||||
else if (flag == null) {
|
||||
if (logger.isWarnEnabled() && !containsBean(beanName)) {
|
||||
// inner bean with other scope - can't reliably process events
|
||||
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
|
||||
"but is not reachable for event multicasting by its containing ApplicationContext " +
|
||||
"because it does not have singleton scope. Only top-level listener beans are allowed " +
|
||||
"to be of non-singleton scope.");
|
||||
}
|
||||
this.singletonNames.put(beanName, Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,18 +19,11 @@ package org.springframework.context.support;
|
|||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
|
|
@ -55,14 +48,10 @@ import org.springframework.context.ResourceLoaderAware;
|
|||
* @see org.springframework.context.ApplicationContextAware
|
||||
* @see org.springframework.context.support.AbstractApplicationContext#refresh()
|
||||
*/
|
||||
class ApplicationContextAwareProcessor implements MergedBeanDefinitionPostProcessor {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
class ApplicationContextAwareProcessor implements BeanPostProcessor {
|
||||
|
||||
private final ConfigurableApplicationContext applicationContext;
|
||||
|
||||
private final Map<String, Boolean> singletonNames = new ConcurrentHashMap<String, Boolean>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ApplicationContextAwareProcessor for the given context.
|
||||
|
|
@ -72,12 +61,6 @@ class ApplicationContextAwareProcessor implements MergedBeanDefinitionPostProces
|
|||
}
|
||||
|
||||
|
||||
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {
|
||||
if (beanDefinition.isSingleton()) {
|
||||
this.singletonNames.put(beanName, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
|
||||
AccessControlContext acc = null;
|
||||
|
||||
|
|
@ -118,24 +101,6 @@ class ApplicationContextAwareProcessor implements MergedBeanDefinitionPostProces
|
|||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
if (bean instanceof ApplicationListener) {
|
||||
// potentially not detected as a listener by getBeanNamesForType retrieval
|
||||
Boolean flag = this.singletonNames.get(beanName);
|
||||
if (Boolean.TRUE.equals(flag)) {
|
||||
// singleton bean (top-level or inner): register on the fly
|
||||
this.applicationContext.addApplicationListener((ApplicationListener) bean);
|
||||
}
|
||||
else if (flag == null) {
|
||||
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
|
||||
// inner bean with other scope - can't reliably process events
|
||||
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
|
||||
"but is not reachable for event multicasting by its containing ApplicationContext " +
|
||||
"because it does not have singleton scope. Only top-level listener beans are allowed " +
|
||||
"to be of non-singleton scope.");
|
||||
}
|
||||
this.singletonNames.put(beanName, Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue