MergedBeanDefinitionPostProcessors apply after all other post-processors (for @PostConstruct to be invoked after other BPPs; SPR-6066)

git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@2366 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
Juergen Hoeller 2009-11-12 01:43:34 +00:00
parent e03687cc19
commit c9d74e4eb4
2 changed files with 92 additions and 14 deletions

View File

@ -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<String,String> 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<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
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<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
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<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
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);
}
/**

View File

@ -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;