From 4d09809f1707765375f7c05726a426decf815f2f Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 3 Feb 2010 23:52:56 +0000 Subject: [PATCH] ApplicationListeners will reliably get invoked through their proxy (if any) --- .../support/AbstractApplicationContext.java | 46 +++++++++++++++++++ .../ApplicationContextAwareProcessor.java | 39 +--------------- 2 files changed, 48 insertions(+), 37 deletions(-) diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java index 57fe139254b..3f374ed31d7 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java @@ -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 singletonNames = new ConcurrentHashMap(); + + 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; + } + } + } diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java b/org.springframework.context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java index 3196066fe31..7e1da6a5e56 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java +++ b/org.springframework.context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java @@ -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 singletonNames = new ConcurrentHashMap(); - /** * 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; }