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