A BeanDefinitionRegistryPostProcessor may register other BeanDefinitionRegistryPostProcessors
We're using the same subtle PriorityOrdered/Ordered/non-ordered separation as for regular BeanFactoryPostProcessors and BeanPostProcessors now. Additionally, we're re-detecting BeanDefinitionRegistryPostProcessor bean names after every invocation phase, up until no further ones appear. Issue: SPR-10630
This commit is contained in:
parent
bb18f81b50
commit
bb971cecf1
|
@ -91,7 +91,7 @@ import static org.springframework.context.annotation.AnnotationConfigUtils.*;
|
|||
* @since 3.0
|
||||
*/
|
||||
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
|
||||
ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware, Ordered {
|
||||
ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware, PriorityOrdered {
|
||||
|
||||
private static final String IMPORT_AWARE_PROCESSOR_BEAN_NAME =
|
||||
ConfigurationClassPostProcessor.class.getName() + ".importAwareProcessor";
|
||||
|
@ -377,7 +377,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
|||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
return Ordered.LOWEST_PRECEDENCE; // within PriorityOrdered
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,14 +21,11 @@ import java.lang.annotation.Annotation;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
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;
|
||||
|
@ -39,12 +36,7 @@ import org.springframework.beans.factory.DisposableBean;
|
|||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
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.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;
|
||||
|
@ -70,9 +62,6 @@ import org.springframework.context.event.SimpleApplicationEventMulticaster;
|
|||
import org.springframework.context.expression.StandardBeanExpressionResolver;
|
||||
import org.springframework.context.weaving.LoadTimeWeaverAware;
|
||||
import org.springframework.context.weaving.LoadTimeWeaverAwareProcessor;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
@ -617,96 +606,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
* <p>Must be called before singleton instantiation.
|
||||
*/
|
||||
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
|
||||
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
|
||||
Set<String> processedBeans = new HashSet<String>();
|
||||
if (beanFactory instanceof BeanDefinitionRegistry) {
|
||||
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
|
||||
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
|
||||
List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =
|
||||
new LinkedList<BeanDefinitionRegistryPostProcessor>();
|
||||
for (BeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) {
|
||||
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
|
||||
BeanDefinitionRegistryPostProcessor registryPostProcessor =
|
||||
(BeanDefinitionRegistryPostProcessor) postProcessor;
|
||||
registryPostProcessor.postProcessBeanDefinitionRegistry(registry);
|
||||
registryPostProcessors.add(registryPostProcessor);
|
||||
}
|
||||
else {
|
||||
regularPostProcessors.add(postProcessor);
|
||||
}
|
||||
}
|
||||
Map<String, BeanDefinitionRegistryPostProcessor> beanMap =
|
||||
beanFactory.getBeansOfType(BeanDefinitionRegistryPostProcessor.class, true, false);
|
||||
List<BeanDefinitionRegistryPostProcessor> registryPostProcessorBeans =
|
||||
new ArrayList<BeanDefinitionRegistryPostProcessor>(beanMap.values());
|
||||
OrderComparator.sort(registryPostProcessorBeans);
|
||||
for (BeanDefinitionRegistryPostProcessor postProcessor : registryPostProcessorBeans) {
|
||||
postProcessor.postProcessBeanDefinitionRegistry(registry);
|
||||
}
|
||||
invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
|
||||
invokeBeanFactoryPostProcessors(registryPostProcessorBeans, beanFactory);
|
||||
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
|
||||
processedBeans.addAll(beanMap.keySet());
|
||||
}
|
||||
else {
|
||||
// Invoke factory processors registered with the context instance.
|
||||
invokeBeanFactoryPostProcessors(getBeanFactoryPostProcessors(), beanFactory);
|
||||
}
|
||||
|
||||
// Do not initialize FactoryBeans here: We need to leave all regular beans
|
||||
// uninitialized to let the bean factory post-processors apply to them!
|
||||
String[] postProcessorNames =
|
||||
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
|
||||
|
||||
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
|
||||
// Ordered, and the rest.
|
||||
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
|
||||
List<String> orderedPostProcessorNames = new ArrayList<String>();
|
||||
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
|
||||
for (String ppName : postProcessorNames) {
|
||||
if (processedBeans.contains(ppName)) {
|
||||
// skip - already processed in first phase above
|
||||
}
|
||||
else if (isTypeMatch(ppName, PriorityOrdered.class)) {
|
||||
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
|
||||
}
|
||||
else if (isTypeMatch(ppName, Ordered.class)) {
|
||||
orderedPostProcessorNames.add(ppName);
|
||||
}
|
||||
else {
|
||||
nonOrderedPostProcessorNames.add(ppName);
|
||||
}
|
||||
}
|
||||
|
||||
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
|
||||
OrderComparator.sort(priorityOrderedPostProcessors);
|
||||
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
|
||||
|
||||
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
|
||||
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
|
||||
for (String postProcessorName : orderedPostProcessorNames) {
|
||||
orderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.class));
|
||||
}
|
||||
OrderComparator.sort(orderedPostProcessors);
|
||||
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
|
||||
|
||||
// Finally, invoke all other BeanFactoryPostProcessors.
|
||||
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
|
||||
for (String postProcessorName : nonOrderedPostProcessorNames) {
|
||||
nonOrderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.class));
|
||||
}
|
||||
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the given BeanFactoryPostProcessor beans.
|
||||
*/
|
||||
private void invokeBeanFactoryPostProcessors(
|
||||
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
|
||||
|
||||
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
|
||||
postProcessor.postProcessBeanFactory(beanFactory);
|
||||
}
|
||||
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -715,79 +615,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
* <p>Must be called before any instantiation of application beans.
|
||||
*/
|
||||
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
|
||||
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
|
||||
|
||||
// Register BeanPostProcessorChecker that logs an info message when
|
||||
// a bean is created during BeanPostProcessor instantiation, i.e. when
|
||||
// a bean is not eligible for getting processed by all BeanPostProcessors.
|
||||
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
|
||||
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
|
||||
|
||||
// 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)) {
|
||||
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);
|
||||
}
|
||||
else {
|
||||
nonOrderedPostProcessorNames.add(ppName);
|
||||
}
|
||||
}
|
||||
|
||||
// First, register the BeanPostProcessors that implement PriorityOrdered.
|
||||
OrderComparator.sort(priorityOrderedPostProcessors);
|
||||
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
|
||||
|
||||
// Next, register the BeanPostProcessors that implement Ordered.
|
||||
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
|
||||
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);
|
||||
|
||||
// Now, register all regular BeanPostProcessors.
|
||||
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
|
||||
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);
|
||||
|
||||
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the given BeanPostProcessor beans.
|
||||
*/
|
||||
private void registerBeanPostProcessors(
|
||||
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
|
||||
|
||||
for (BeanPostProcessor postProcessor : postProcessors) {
|
||||
beanFactory.addBeanPostProcessor(postProcessor);
|
||||
}
|
||||
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1415,85 +1243,4 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* BeanPostProcessor that logs an info message when a bean is created during
|
||||
* BeanPostProcessor instantiation, i.e. when a bean is not eligible for
|
||||
* getting processed by all BeanPostProcessors.
|
||||
*/
|
||||
private class BeanPostProcessorChecker implements BeanPostProcessor {
|
||||
|
||||
private final ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
private final int beanPostProcessorTargetCount;
|
||||
|
||||
public BeanPostProcessorChecker(ConfigurableListableBeanFactory beanFactory, int beanPostProcessorTargetCount) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.beanPostProcessorTargetCount = beanPostProcessorTargetCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
if (bean != null && !(bean instanceof BeanPostProcessor) &&
|
||||
this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Bean '" + beanName + "' of type [" + bean.getClass() +
|
||||
"] is not eligible for getting processed by all BeanPostProcessors " +
|
||||
"(for example: not eligible for auto-proxying)");
|
||||
}
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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>(64);
|
||||
|
||||
@Override
|
||||
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
|
||||
if (beanDefinition.isSingleton()) {
|
||||
this.singletonNames.put(beanName, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,370 @@
|
|||
/*
|
||||
* Copyright 2002-2013 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.context.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
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;
|
||||
|
||||
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.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.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
|
||||
/**
|
||||
* Delegate for AbstractApplicationContext's post-processor handling.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
*/
|
||||
class PostProcessorRegistrationDelegate {
|
||||
|
||||
public static void invokeBeanFactoryPostProcessors(
|
||||
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
|
||||
|
||||
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
|
||||
Set<String> processedBeans = new HashSet<String>();
|
||||
|
||||
if (beanFactory instanceof BeanDefinitionRegistry) {
|
||||
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
|
||||
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
|
||||
List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =
|
||||
new LinkedList<BeanDefinitionRegistryPostProcessor>();
|
||||
|
||||
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
|
||||
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
|
||||
BeanDefinitionRegistryPostProcessor registryPostProcessor =
|
||||
(BeanDefinitionRegistryPostProcessor) postProcessor;
|
||||
registryPostProcessor.postProcessBeanDefinitionRegistry(registry);
|
||||
registryPostProcessors.add(registryPostProcessor);
|
||||
}
|
||||
else {
|
||||
regularPostProcessors.add(postProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
// Do not initialize FactoryBeans here: We need to leave all regular beans
|
||||
// uninitialized to let the bean factory post-processors apply to them!
|
||||
// Separate between BeanDefinitionRegistryPostProcessors that implement
|
||||
// PriorityOrdered, Ordered, and the rest.
|
||||
String[] postProcessorNames =
|
||||
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
|
||||
|
||||
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
|
||||
List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
|
||||
for (String ppName : postProcessorNames) {
|
||||
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
|
||||
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
|
||||
processedBeans.add(ppName);
|
||||
}
|
||||
}
|
||||
OrderComparator.sort(priorityOrderedPostProcessors);
|
||||
registryPostProcessors.addAll(priorityOrderedPostProcessors);
|
||||
invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
|
||||
|
||||
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
|
||||
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
|
||||
List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
|
||||
for (String ppName : postProcessorNames) {
|
||||
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
|
||||
orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
|
||||
processedBeans.add(ppName);
|
||||
}
|
||||
}
|
||||
OrderComparator.sort(orderedPostProcessors);
|
||||
registryPostProcessors.addAll(orderedPostProcessors);
|
||||
invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);
|
||||
|
||||
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
|
||||
boolean reiterate = true;
|
||||
while (reiterate) {
|
||||
reiterate = false;
|
||||
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
|
||||
for (String ppName : postProcessorNames) {
|
||||
if (!processedBeans.contains(ppName)) {
|
||||
BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
|
||||
registryPostProcessors.add(pp);
|
||||
processedBeans.add(ppName);
|
||||
pp.postProcessBeanDefinitionRegistry(registry);
|
||||
reiterate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
|
||||
invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
|
||||
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
|
||||
}
|
||||
|
||||
else {
|
||||
// Invoke factory processors registered with the context instance.
|
||||
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
|
||||
}
|
||||
|
||||
// Do not initialize FactoryBeans here: We need to leave all regular beans
|
||||
// uninitialized to let the bean factory post-processors apply to them!
|
||||
String[] postProcessorNames =
|
||||
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
|
||||
|
||||
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
|
||||
// Ordered, and the rest.
|
||||
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
|
||||
List<String> orderedPostProcessorNames = new ArrayList<String>();
|
||||
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
|
||||
for (String ppName : postProcessorNames) {
|
||||
if (processedBeans.contains(ppName)) {
|
||||
// skip - already processed in first phase above
|
||||
}
|
||||
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
|
||||
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
|
||||
}
|
||||
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
|
||||
orderedPostProcessorNames.add(ppName);
|
||||
}
|
||||
else {
|
||||
nonOrderedPostProcessorNames.add(ppName);
|
||||
}
|
||||
}
|
||||
|
||||
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
|
||||
OrderComparator.sort(priorityOrderedPostProcessors);
|
||||
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
|
||||
|
||||
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
|
||||
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
|
||||
for (String postProcessorName : orderedPostProcessorNames) {
|
||||
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
|
||||
}
|
||||
OrderComparator.sort(orderedPostProcessors);
|
||||
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
|
||||
|
||||
// Finally, invoke all other BeanFactoryPostProcessors.
|
||||
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
|
||||
for (String postProcessorName : nonOrderedPostProcessorNames) {
|
||||
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
|
||||
}
|
||||
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
|
||||
}
|
||||
|
||||
public static void registerBeanPostProcessors(
|
||||
ConfigurableListableBeanFactory beanFactory, ConfigurableApplicationContext applicationContext) {
|
||||
|
||||
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
|
||||
|
||||
// Register BeanPostProcessorChecker that logs an info message when
|
||||
// a bean is created during BeanPostProcessor instantiation, i.e. when
|
||||
// a bean is not eligible for getting processed by all BeanPostProcessors.
|
||||
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
|
||||
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
|
||||
|
||||
// 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 (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
|
||||
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
|
||||
priorityOrderedPostProcessors.add(pp);
|
||||
if (pp instanceof MergedBeanDefinitionPostProcessor) {
|
||||
internalPostProcessors.add(pp);
|
||||
}
|
||||
}
|
||||
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
|
||||
orderedPostProcessorNames.add(ppName);
|
||||
}
|
||||
else {
|
||||
nonOrderedPostProcessorNames.add(ppName);
|
||||
}
|
||||
}
|
||||
|
||||
// First, register the BeanPostProcessors that implement PriorityOrdered.
|
||||
OrderComparator.sort(priorityOrderedPostProcessors);
|
||||
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
|
||||
|
||||
// Next, register the BeanPostProcessors that implement Ordered.
|
||||
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
|
||||
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);
|
||||
|
||||
// Now, register all regular BeanPostProcessors.
|
||||
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
|
||||
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);
|
||||
|
||||
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the given BeanDefinitionRegistryPostProcessor beans.
|
||||
*/
|
||||
private static void invokeBeanDefinitionRegistryPostProcessors(
|
||||
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
|
||||
|
||||
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
|
||||
postProcessor.postProcessBeanDefinitionRegistry(registry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the given BeanFactoryPostProcessor beans.
|
||||
*/
|
||||
private static void invokeBeanFactoryPostProcessors(
|
||||
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
|
||||
|
||||
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
|
||||
postProcessor.postProcessBeanFactory(beanFactory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the given BeanPostProcessor beans.
|
||||
*/
|
||||
private static void registerBeanPostProcessors(
|
||||
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
|
||||
|
||||
for (BeanPostProcessor postProcessor : postProcessors) {
|
||||
beanFactory.addBeanPostProcessor(postProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* BeanPostProcessor that logs an info message when a bean is created during
|
||||
* BeanPostProcessor instantiation, i.e. when a bean is not eligible for
|
||||
* getting processed by all BeanPostProcessors.
|
||||
*/
|
||||
private static class BeanPostProcessorChecker implements BeanPostProcessor {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(BeanPostProcessorChecker.class);
|
||||
|
||||
private final ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
private final int beanPostProcessorTargetCount;
|
||||
|
||||
public BeanPostProcessorChecker(ConfigurableListableBeanFactory beanFactory, int beanPostProcessorTargetCount) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.beanPostProcessorTargetCount = beanPostProcessorTargetCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
if (bean != null && !(bean instanceof BeanPostProcessor) &&
|
||||
this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Bean '" + beanName + "' of type [" + bean.getClass() +
|
||||
"] is not eligible for getting processed by all BeanPostProcessors " +
|
||||
"(for example: not eligible for auto-proxying)");
|
||||
}
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* BeanPostProcessor that detects beans which implement the ApplicationListener interface.
|
||||
* This catches beans that can't reliably be detected by getBeanNamesForType.
|
||||
*/
|
||||
private static class ApplicationListenerDetector implements MergedBeanDefinitionPostProcessor {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ApplicationListenerDetector.class);
|
||||
|
||||
private final ConfigurableApplicationContext applicationContext;
|
||||
|
||||
private final Map<String, Boolean> singletonNames = new ConcurrentHashMap<String, Boolean>(64);
|
||||
|
||||
public ApplicationListenerDetector(ConfigurableApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
|
||||
if (beanDefinition.isSingleton()) {
|
||||
this.singletonNames.put(beanName, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -21,15 +21,12 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
@ -38,25 +35,19 @@ import static org.hamcrest.Matchers.*;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests for {@link Conditional} beans.
|
||||
* Test for {@link Conditional} beans.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public class ConfigurationClassWithConditionTests {
|
||||
|
||||
private final AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@After
|
||||
public void closeContext() {
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void conditionalOnMissingBeanMatch() throws Exception {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(BeanOneConfiguration.class, BeanTwoConfiguration.class);
|
||||
ctx.refresh();
|
||||
assertTrue(ctx.containsBean("bean1"));
|
||||
|
@ -66,6 +57,7 @@ public class ConfigurationClassWithConditionTests {
|
|||
|
||||
@Test
|
||||
public void conditionalOnMissingBeanNoMatch() throws Exception {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(BeanTwoConfiguration.class);
|
||||
ctx.refresh();
|
||||
assertFalse(ctx.containsBean("bean1"));
|
||||
|
@ -75,6 +67,7 @@ public class ConfigurationClassWithConditionTests {
|
|||
|
||||
@Test
|
||||
public void conditionalOnBeanMatch() throws Exception {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(BeanOneConfiguration.class, BeanThreeConfiguration.class);
|
||||
ctx.refresh();
|
||||
assertTrue(ctx.containsBean("bean1"));
|
||||
|
@ -83,6 +76,7 @@ public class ConfigurationClassWithConditionTests {
|
|||
|
||||
@Test
|
||||
public void conditionalOnBeanNoMatch() throws Exception {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(BeanThreeConfiguration.class);
|
||||
ctx.refresh();
|
||||
assertFalse(ctx.containsBean("bean1"));
|
||||
|
@ -91,6 +85,7 @@ public class ConfigurationClassWithConditionTests {
|
|||
|
||||
@Test
|
||||
public void metaConditional() throws Exception {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigurationWithMetaCondition.class);
|
||||
ctx.refresh();
|
||||
assertTrue(ctx.containsBean("bean"));
|
||||
|
@ -98,6 +93,7 @@ public class ConfigurationClassWithConditionTests {
|
|||
|
||||
@Test
|
||||
public void nonConfigurationClass() throws Exception {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(NonConfigurationClass.class);
|
||||
ctx.refresh();
|
||||
thrown.expect(NoSuchBeanDefinitionException.class);
|
||||
|
@ -106,6 +102,7 @@ public class ConfigurationClassWithConditionTests {
|
|||
|
||||
@Test
|
||||
public void methodConditional() throws Exception {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConditionOnMethodConfiguration.class);
|
||||
ctx.refresh();
|
||||
thrown.expect(NoSuchBeanDefinitionException.class);
|
||||
|
@ -119,25 +116,6 @@ public class ConfigurationClassWithConditionTests {
|
|||
ctx.refresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void importsNotLoaded() throws Exception {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ImportsNotLoaded.class);
|
||||
ctx.refresh();
|
||||
assertThat(ctx.containsBeanDefinition("a"), equalTo(false));
|
||||
assertThat(ctx.containsBeanDefinition("b"), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sensibleConditionContext() throws Exception {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.setResourceLoader(new DefaultResourceLoader());
|
||||
ctx.setClassLoader(getClass().getClassLoader());
|
||||
ctx.register(SensibleConditionContext.class);
|
||||
ctx.refresh();
|
||||
assertThat(ctx.getBean(ExampleBean.class), instanceOf(ExampleBean.class));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class BeanOneConfiguration {
|
||||
@Bean
|
||||
|
@ -279,70 +257,6 @@ public class ConfigurationClassWithConditionTests {
|
|||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Never
|
||||
@Import({ ConfigurationNotLoaded.class, RegistrarNotLoaded.class, ImportSelectorNotLoaded.class })
|
||||
static class ImportsNotLoaded {
|
||||
static {
|
||||
if (true) throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ConfigurationNotLoaded {
|
||||
@Bean
|
||||
public String a() {
|
||||
return "a";
|
||||
}
|
||||
}
|
||||
|
||||
static class RegistrarNotLoaded implements ImportBeanDefinitionRegistrar {
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
|
||||
BeanDefinitionRegistry registry) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
static class ImportSelectorNotLoaded implements ImportSelector {
|
||||
|
||||
@Override
|
||||
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||
return new String[] { SelectedConfigurationNotLoaded.class.getName() };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class SelectedConfigurationNotLoaded {
|
||||
@Bean
|
||||
public String b() {
|
||||
return "b";
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Conditional(SensibleConditionContextCondition.class)
|
||||
static class SensibleConditionContext {
|
||||
@Bean
|
||||
ExampleBean exampleBean() {
|
||||
return new ExampleBean();
|
||||
}
|
||||
}
|
||||
|
||||
static class SensibleConditionContextCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
assertThat(context.getBeanFactory(), notNullValue());
|
||||
assertThat(context.getClassLoader(), notNullValue());
|
||||
assertThat(context.getEnvironment(), notNullValue());
|
||||
assertThat(context.getRegistry(), notNullValue());
|
||||
assertThat(context.getResourceLoader(), notNullValue());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static class ExampleBean {
|
||||
}
|
||||
|
||||
|
|
|
@ -16,19 +16,22 @@
|
|||
|
||||
package org.springframework.context.support;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests the interaction between {@link ApplicationContext} implementations and
|
||||
|
@ -93,6 +96,29 @@ public class BeanFactoryPostProcessorTests {
|
|||
assertFalse(bfpp.wasCalled);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeanDefinitionRegistryPostProcessor() throws Exception {
|
||||
StaticApplicationContext ac = new StaticApplicationContext();
|
||||
ac.registerSingleton("tb1", TestBean.class);
|
||||
ac.registerSingleton("tb2", TestBean.class);
|
||||
TestBeanDefinitionRegistryPostProcessor bdrpp = new TestBeanDefinitionRegistryPostProcessor();
|
||||
ac.addBeanFactoryPostProcessor(bdrpp);
|
||||
assertFalse(bdrpp.wasCalled);
|
||||
ac.refresh();
|
||||
assertTrue(bdrpp.wasCalled);
|
||||
assertTrue(ac.getBean(TestBeanFactoryPostProcessor.class).wasCalled);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeanDefinitionRegistryPostProcessorRegisteringAnother() throws Exception {
|
||||
StaticApplicationContext ac = new StaticApplicationContext();
|
||||
ac.registerSingleton("tb1", TestBean.class);
|
||||
ac.registerSingleton("tb2", TestBean.class);
|
||||
ac.registerBeanDefinition("bdrpp2", new RootBeanDefinition(TestBeanDefinitionRegistryPostProcessor2.class));
|
||||
ac.refresh();
|
||||
assertTrue(ac.getBean(TestBeanFactoryPostProcessor.class).wasCalled);
|
||||
}
|
||||
|
||||
|
||||
public static class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
|
||||
|
||||
|
@ -110,4 +136,38 @@ public class BeanFactoryPostProcessorTests {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
|
||||
|
||||
public boolean wasCalled;
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
registry.registerBeanDefinition("bfpp", new RootBeanDefinition(TestBeanFactoryPostProcessor.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
this.wasCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class TestBeanDefinitionRegistryPostProcessor2 implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
registry.registerBeanDefinition("anotherpp", new RootBeanDefinition(TestBeanDefinitionRegistryPostProcessor.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return HIGHEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue