diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
index 834d40ee8e3..7e67b3ace27 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
@@ -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
}
diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
index fc2032f905e..4387432d9ab 100644
--- a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
+++ b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
@@ -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
*
Must be called before singleton instantiation.
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
- // Invoke BeanDefinitionRegistryPostProcessors first, if any.
- Set processedBeans = new HashSet();
- if (beanFactory instanceof BeanDefinitionRegistry) {
- BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
- List regularPostProcessors = new LinkedList();
- List registryPostProcessors =
- new LinkedList();
- for (BeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) {
- if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
- BeanDefinitionRegistryPostProcessor registryPostProcessor =
- (BeanDefinitionRegistryPostProcessor) postProcessor;
- registryPostProcessor.postProcessBeanDefinitionRegistry(registry);
- registryPostProcessors.add(registryPostProcessor);
- }
- else {
- regularPostProcessors.add(postProcessor);
- }
- }
- Map beanMap =
- beanFactory.getBeansOfType(BeanDefinitionRegistryPostProcessor.class, true, false);
- List registryPostProcessorBeans =
- new ArrayList(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 priorityOrderedPostProcessors = new ArrayList();
- List orderedPostProcessorNames = new ArrayList();
- List nonOrderedPostProcessorNames = new ArrayList();
- 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 orderedPostProcessors = new ArrayList();
- for (String postProcessorName : orderedPostProcessorNames) {
- orderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.class));
- }
- OrderComparator.sort(orderedPostProcessors);
- invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
-
- // Finally, invoke all other BeanFactoryPostProcessors.
- List nonOrderedPostProcessors = new ArrayList();
- 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
* 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 priorityOrderedPostProcessors = new ArrayList();
- List internalPostProcessors = new ArrayList();
- List orderedPostProcessorNames = new ArrayList();
- List nonOrderedPostProcessorNames = new ArrayList();
- 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 orderedPostProcessors = new ArrayList();
- 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 nonOrderedPostProcessors = new ArrayList();
- 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 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 singletonNames = new ConcurrentHashMap(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;
- }
- }
-
}
diff --git a/spring-context/src/main/java/org/springframework/context/support/PostProcessorRegistrationDelegate.java b/spring-context/src/main/java/org/springframework/context/support/PostProcessorRegistrationDelegate.java
new file mode 100644
index 00000000000..f0b4a4b5a92
--- /dev/null
+++ b/spring-context/src/main/java/org/springframework/context/support/PostProcessorRegistrationDelegate.java
@@ -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 beanFactoryPostProcessors) {
+
+ // Invoke BeanDefinitionRegistryPostProcessors first, if any.
+ Set processedBeans = new HashSet();
+
+ if (beanFactory instanceof BeanDefinitionRegistry) {
+ BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
+ List regularPostProcessors = new LinkedList();
+ List registryPostProcessors =
+ new LinkedList();
+
+ 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 priorityOrderedPostProcessors = new ArrayList();
+ 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 orderedPostProcessors = new ArrayList();
+ 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 priorityOrderedPostProcessors = new ArrayList();
+ List orderedPostProcessorNames = new ArrayList();
+ List nonOrderedPostProcessorNames = new ArrayList();
+ 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 orderedPostProcessors = new ArrayList();
+ for (String postProcessorName : orderedPostProcessorNames) {
+ orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
+ }
+ OrderComparator.sort(orderedPostProcessors);
+ invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
+
+ // Finally, invoke all other BeanFactoryPostProcessors.
+ List nonOrderedPostProcessors = new ArrayList();
+ 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 priorityOrderedPostProcessors = new ArrayList();
+ List internalPostProcessors = new ArrayList();
+ List orderedPostProcessorNames = new ArrayList();
+ List nonOrderedPostProcessorNames = new ArrayList();
+ 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 orderedPostProcessors = new ArrayList();
+ 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 nonOrderedPostProcessors = new ArrayList();
+ 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 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 singletonNames = new ConcurrentHashMap(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;
+ }
+ }
+
+}
diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassWithConditionTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassWithConditionTests.java
index 2ce7ecab781..3deaf61d0ce 100644
--- a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassWithConditionTests.java
+++ b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassWithConditionTests.java
@@ -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 {
}
diff --git a/spring-context/src/test/java/org/springframework/context/support/BeanFactoryPostProcessorTests.java b/spring-context/src/test/java/org/springframework/context/support/BeanFactoryPostProcessorTests.java
index 152ecfb6ecd..b68aef069d6 100644
--- a/spring-context/src/test/java/org/springframework/context/support/BeanFactoryPostProcessorTests.java
+++ b/spring-context/src/test/java/org/springframework/context/support/BeanFactoryPostProcessorTests.java
@@ -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;
+ }
+ }
+
}