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 1747b8fa455..4a91e556e30 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 @@ -37,6 +37,7 @@ import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; import org.springframework.beans.support.ResourceEditorRegistrar; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -502,14 +503,16 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader } catch (AccessControlException ex) { systemProperties = new ReadOnlySystemAttributesMap() { - @Override protected String getSystemAttribute(String propertyName) { try { return System.getProperty(propertyName); - } catch (AccessControlException ex) { - logger.info("Not allowed to obtain system property [" + propertyName + "]: " - + ex.getMessage()); + } + catch (AccessControlException ex) { + if (logger.isInfoEnabled()) { + logger.info("Not allowed to obtain system property [" + propertyName + "]: " + + ex.getMessage()); + } return null; } } @@ -517,6 +520,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader } beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, systemProperties); } + if (!beanFactory.containsBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { Map systemEnvironment; try { @@ -528,9 +532,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader protected String getSystemAttribute(String variableName) { try { return System.getenv(variableName); - } catch (AccessControlException ex) { - logger.info("Not allowed to obtain system environment variable [" + variableName + "]: " + - ex.getMessage()); + } + catch (AccessControlException ex) { + if (logger.isInfoEnabled()) { + logger.info("Not allowed to obtain system environment variable [" + variableName + "]: " + + ex.getMessage()); + } return null; } } @@ -629,11 +636,16 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader // Separate between BeanPostProcessors that implement PriorityOrdered, // Ordered, and the rest. List priorityOrderedPostProcessors = new ArrayList(); + List internalPostProcessors = new ArrayList(); List orderedPostProcessorNames = new ArrayList(); List nonOrderedPostProcessorNames = new ArrayList(); for (String ppName : postProcessorNames) { if (isTypeMatch(ppName, PriorityOrdered.class)) { - priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanPostProcessor.class)); + BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); + priorityOrderedPostProcessors.add(pp); + if (pp instanceof MergedBeanDefinitionPostProcessor) { + internalPostProcessors.add(pp); + } } else if (isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); @@ -649,18 +661,30 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader // Next, register the BeanPostProcessors that implement Ordered. List orderedPostProcessors = new ArrayList(); - for (String postProcessorName : orderedPostProcessorNames) { - orderedPostProcessors.add(getBean(postProcessorName, BeanPostProcessor.class)); + for (String ppName : orderedPostProcessorNames) { + BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); + orderedPostProcessors.add(pp); + if (pp instanceof MergedBeanDefinitionPostProcessor) { + internalPostProcessors.add(pp); + } } OrderComparator.sort(orderedPostProcessors); registerBeanPostProcessors(beanFactory, orderedPostProcessors); - // Finally, register all other BeanPostProcessors. + // Now, register all regular BeanPostProcessors. List nonOrderedPostProcessors = new ArrayList(); - for (String postProcessorName : nonOrderedPostProcessorNames) { - nonOrderedPostProcessors.add(getBean(postProcessorName, BeanPostProcessor.class)); + for (String ppName : nonOrderedPostProcessorNames) { + BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); + nonOrderedPostProcessors.add(pp); + if (pp instanceof MergedBeanDefinitionPostProcessor) { + internalPostProcessors.add(pp); + } } registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); + + // Finally, re-register all internal BeanPostProcessors. + OrderComparator.sort(internalPostProcessors); + registerBeanPostProcessors(beanFactory, internalPostProcessors); } /** diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java index 35b736cfccb..00075734ecf 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2009 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. @@ -25,6 +25,7 @@ import javax.ejb.EJB; import static org.junit.Assert.*; import org.junit.Test; +import org.springframework.beans.BeansException; import org.springframework.beans.INestedTestBean; import org.springframework.beans.ITestBean; import org.springframework.beans.NestedTestBean; @@ -33,9 +34,11 @@ import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor; +import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.support.GenericApplicationContext; import org.springframework.jndi.support.SimpleJndiBeanFactory; import org.springframework.mock.jndi.ExpectedLookupTemplate; import org.springframework.util.SerializationTestUtils; @@ -58,6 +61,33 @@ public class CommonAnnotationBeanPostProcessorTests { assertTrue(bean.destroyCalled); } + @Test + public void testPostConstructAndPreDestroyWithPostProcessor() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.addBeanPostProcessor(new InitDestroyBeanPostProcessor()); + bf.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor()); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(AnnotatedInitDestroyBean.class)); + + AnnotatedInitDestroyBean bean = (AnnotatedInitDestroyBean) bf.getBean("annotatedBean"); + assertTrue(bean.initCalled); + bf.destroySingletons(); + assertTrue(bean.destroyCalled); + } + + @Test + public void testPostConstructAndPreDestroyWithApplicationContextAndPostProcessor() { + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.registerBeanDefinition("bpp1", new RootBeanDefinition(InitDestroyBeanPostProcessor.class)); + ctx.registerBeanDefinition("bpp2", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class)); + ctx.registerBeanDefinition("annotatedBean", new RootBeanDefinition(AnnotatedInitDestroyBean.class)); + ctx.refresh(); + + AnnotatedInitDestroyBean bean = (AnnotatedInitDestroyBean) ctx.getBean("annotatedBean"); + assertTrue(bean.initCalled); + ctx.close(); + assertTrue(bean.destroyCalled); + } + @Test public void testPostConstructAndPreDestroyWithManualConfiguration() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); @@ -335,6 +365,30 @@ public class CommonAnnotationBeanPostProcessorTests { } + public static class InitDestroyBeanPostProcessor implements DestructionAwareBeanPostProcessor { + + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof AnnotatedInitDestroyBean) { + assertFalse(((AnnotatedInitDestroyBean) bean).initCalled); + } + return bean; + } + + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof AnnotatedInitDestroyBean) { + assertTrue(((AnnotatedInitDestroyBean) bean).initCalled); + } + return bean; + } + + public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException { + if (bean instanceof AnnotatedInitDestroyBean) { + assertFalse(((AnnotatedInitDestroyBean) bean).destroyCalled); + } + } + } + + public static class ResourceInjectionBean extends AnnotatedInitDestroyBean { public boolean init2Called = false;