Skip to content

Commit bb971ce

Browse files
committed
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
1 parent bb18f81 commit bb971ce

File tree

5 files changed

+447
-356
lines changed

5 files changed

+447
-356
lines changed

spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
* @since 3.0
9292
*/
9393
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
94-
ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware, Ordered {
94+
ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware, PriorityOrdered {
9595

9696
private static final String IMPORT_AWARE_PROCESSOR_BEAN_NAME =
9797
ConfigurationClassPostProcessor.class.getName() + ".importAwareProcessor";
@@ -377,7 +377,7 @@ public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFact
377377

378378
@Override
379379
public int getOrder() {
380-
return Ordered.HIGHEST_PRECEDENCE;
380+
return Ordered.LOWEST_PRECEDENCE; // within PriorityOrdered
381381
}
382382

383383

spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java

+2-255
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,11 @@
2121
import java.util.ArrayList;
2222
import java.util.Collection;
2323
import java.util.Date;
24-
import java.util.HashSet;
2524
import java.util.LinkedHashSet;
26-
import java.util.LinkedList;
2725
import java.util.List;
2826
import java.util.Locale;
2927
import java.util.Map;
3028
import java.util.Set;
31-
import java.util.concurrent.ConcurrentHashMap;
3229

3330
import org.apache.commons.logging.Log;
3431
import org.apache.commons.logging.LogFactory;
@@ -39,12 +36,7 @@
3936
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
4037
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
4138
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
42-
import org.springframework.beans.factory.config.BeanPostProcessor;
4339
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
44-
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
45-
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
46-
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
47-
import org.springframework.beans.factory.support.RootBeanDefinition;
4840
import org.springframework.beans.support.ResourceEditorRegistrar;
4941
import org.springframework.context.ApplicationContext;
5042
import org.springframework.context.ApplicationContextAware;
@@ -70,9 +62,6 @@
7062
import org.springframework.context.expression.StandardBeanExpressionResolver;
7163
import org.springframework.context.weaving.LoadTimeWeaverAware;
7264
import org.springframework.context.weaving.LoadTimeWeaverAwareProcessor;
73-
import org.springframework.core.OrderComparator;
74-
import org.springframework.core.Ordered;
75-
import org.springframework.core.PriorityOrdered;
7665
import org.springframework.core.convert.ConversionService;
7766
import org.springframework.core.env.ConfigurableEnvironment;
7867
import org.springframework.core.env.Environment;
@@ -617,96 +606,7 @@ protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactor
617606
* <p>Must be called before singleton instantiation.
618607
*/
619608
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
620-
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
621-
Set<String> processedBeans = new HashSet<String>();
622-
if (beanFactory instanceof BeanDefinitionRegistry) {
623-
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
624-
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
625-
List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =
626-
new LinkedList<BeanDefinitionRegistryPostProcessor>();
627-
for (BeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) {
628-
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
629-
BeanDefinitionRegistryPostProcessor registryPostProcessor =
630-
(BeanDefinitionRegistryPostProcessor) postProcessor;
631-
registryPostProcessor.postProcessBeanDefinitionRegistry(registry);
632-
registryPostProcessors.add(registryPostProcessor);
633-
}
634-
else {
635-
regularPostProcessors.add(postProcessor);
636-
}
637-
}
638-
Map<String, BeanDefinitionRegistryPostProcessor> beanMap =
639-
beanFactory.getBeansOfType(BeanDefinitionRegistryPostProcessor.class, true, false);
640-
List<BeanDefinitionRegistryPostProcessor> registryPostProcessorBeans =
641-
new ArrayList<BeanDefinitionRegistryPostProcessor>(beanMap.values());
642-
OrderComparator.sort(registryPostProcessorBeans);
643-
for (BeanDefinitionRegistryPostProcessor postProcessor : registryPostProcessorBeans) {
644-
postProcessor.postProcessBeanDefinitionRegistry(registry);
645-
}
646-
invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
647-
invokeBeanFactoryPostProcessors(registryPostProcessorBeans, beanFactory);
648-
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
649-
processedBeans.addAll(beanMap.keySet());
650-
}
651-
else {
652-
// Invoke factory processors registered with the context instance.
653-
invokeBeanFactoryPostProcessors(getBeanFactoryPostProcessors(), beanFactory);
654-
}
655-
656-
// Do not initialize FactoryBeans here: We need to leave all regular beans
657-
// uninitialized to let the bean factory post-processors apply to them!
658-
String[] postProcessorNames =
659-
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
660-
661-
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
662-
// Ordered, and the rest.
663-
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
664-
List<String> orderedPostProcessorNames = new ArrayList<String>();
665-
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
666-
for (String ppName : postProcessorNames) {
667-
if (processedBeans.contains(ppName)) {
668-
// skip - already processed in first phase above
669-
}
670-
else if (isTypeMatch(ppName, PriorityOrdered.class)) {
671-
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
672-
}
673-
else if (isTypeMatch(ppName, Ordered.class)) {
674-
orderedPostProcessorNames.add(ppName);
675-
}
676-
else {
677-
nonOrderedPostProcessorNames.add(ppName);
678-
}
679-
}
680-
681-
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
682-
OrderComparator.sort(priorityOrderedPostProcessors);
683-
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
684-
685-
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
686-
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
687-
for (String postProcessorName : orderedPostProcessorNames) {
688-
orderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.class));
689-
}
690-
OrderComparator.sort(orderedPostProcessors);
691-
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
692-
693-
// Finally, invoke all other BeanFactoryPostProcessors.
694-
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
695-
for (String postProcessorName : nonOrderedPostProcessorNames) {
696-
nonOrderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.class));
697-
}
698-
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
699-
}
700-
701-
/**
702-
* Invoke the given BeanFactoryPostProcessor beans.
703-
*/
704-
private void invokeBeanFactoryPostProcessors(
705-
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
706-
707-
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
708-
postProcessor.postProcessBeanFactory(beanFactory);
709-
}
609+
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
710610
}
711611

712612
/**
@@ -715,79 +615,7 @@ private void invokeBeanFactoryPostProcessors(
715615
* <p>Must be called before any instantiation of application beans.
716616
*/
717617
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
718-
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
719-
720-
// Register BeanPostProcessorChecker that logs an info message when
721-
// a bean is created during BeanPostProcessor instantiation, i.e. when
722-
// a bean is not eligible for getting processed by all BeanPostProcessors.
723-
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
724-
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
725-
726-
// Separate between BeanPostProcessors that implement PriorityOrdered,
727-
// Ordered, and the rest.
728-
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
729-
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
730-
List<String> orderedPostProcessorNames = new ArrayList<String>();
731-
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
732-
for (String ppName : postProcessorNames) {
733-
if (isTypeMatch(ppName, PriorityOrdered.class)) {
734-
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
735-
priorityOrderedPostProcessors.add(pp);
736-
if (pp instanceof MergedBeanDefinitionPostProcessor) {
737-
internalPostProcessors.add(pp);
738-
}
739-
}
740-
else if (isTypeMatch(ppName, Ordered.class)) {
741-
orderedPostProcessorNames.add(ppName);
742-
}
743-
else {
744-
nonOrderedPostProcessorNames.add(ppName);
745-
}
746-
}
747-
748-
// First, register the BeanPostProcessors that implement PriorityOrdered.
749-
OrderComparator.sort(priorityOrderedPostProcessors);
750-
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
751-
752-
// Next, register the BeanPostProcessors that implement Ordered.
753-
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
754-
for (String ppName : orderedPostProcessorNames) {
755-
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
756-
orderedPostProcessors.add(pp);
757-
if (pp instanceof MergedBeanDefinitionPostProcessor) {
758-
internalPostProcessors.add(pp);
759-
}
760-
}
761-
OrderComparator.sort(orderedPostProcessors);
762-
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
763-
764-
// Now, register all regular BeanPostProcessors.
765-
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
766-
for (String ppName : nonOrderedPostProcessorNames) {
767-
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
768-
nonOrderedPostProcessors.add(pp);
769-
if (pp instanceof MergedBeanDefinitionPostProcessor) {
770-
internalPostProcessors.add(pp);
771-
}
772-
}
773-
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
774-
775-
// Finally, re-register all internal BeanPostProcessors.
776-
OrderComparator.sort(internalPostProcessors);
777-
registerBeanPostProcessors(beanFactory, internalPostProcessors);
778-
779-
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector());
780-
}
781-
782-
/**
783-
* Register the given BeanPostProcessor beans.
784-
*/
785-
private void registerBeanPostProcessors(
786-
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
787-
788-
for (BeanPostProcessor postProcessor : postProcessors) {
789-
beanFactory.addBeanPostProcessor(postProcessor);
790-
}
618+
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
791619
}
792620

793621
/**
@@ -1415,85 +1243,4 @@ public String toString() {
14151243
return sb.toString();
14161244
}
14171245

1418-
1419-
/**
1420-
* BeanPostProcessor that logs an info message when a bean is created during
1421-
* BeanPostProcessor instantiation, i.e. when a bean is not eligible for
1422-
* getting processed by all BeanPostProcessors.
1423-
*/
1424-
private class BeanPostProcessorChecker implements BeanPostProcessor {
1425-
1426-
private final ConfigurableListableBeanFactory beanFactory;
1427-
1428-
private final int beanPostProcessorTargetCount;
1429-
1430-
public BeanPostProcessorChecker(ConfigurableListableBeanFactory beanFactory, int beanPostProcessorTargetCount) {
1431-
this.beanFactory = beanFactory;
1432-
this.beanPostProcessorTargetCount = beanPostProcessorTargetCount;
1433-
}
1434-
1435-
@Override
1436-
public Object postProcessBeforeInitialization(Object bean, String beanName) {
1437-
return bean;
1438-
}
1439-
1440-
@Override
1441-
public Object postProcessAfterInitialization(Object bean, String beanName) {
1442-
if (bean != null && !(bean instanceof BeanPostProcessor) &&
1443-
this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
1444-
if (logger.isInfoEnabled()) {
1445-
logger.info("Bean '" + beanName + "' of type [" + bean.getClass() +
1446-
"] is not eligible for getting processed by all BeanPostProcessors " +
1447-
"(for example: not eligible for auto-proxying)");
1448-
}
1449-
}
1450-
return bean;
1451-
}
1452-
}
1453-
1454-
1455-
/**
1456-
* BeanPostProcessor that detects beans which implement the ApplicationListener interface.
1457-
* This catches beans that can't reliably be detected by getBeanNamesForType.
1458-
*/
1459-
private class ApplicationListenerDetector implements MergedBeanDefinitionPostProcessor {
1460-
1461-
private final Map<String, Boolean> singletonNames = new ConcurrentHashMap<String, Boolean>(64);
1462-
1463-
@Override
1464-
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
1465-
if (beanDefinition.isSingleton()) {
1466-
this.singletonNames.put(beanName, Boolean.TRUE);
1467-
}
1468-
}
1469-
1470-
@Override
1471-
public Object postProcessBeforeInitialization(Object bean, String beanName) {
1472-
return bean;
1473-
}
1474-
1475-
@Override
1476-
public Object postProcessAfterInitialization(Object bean, String beanName) {
1477-
if (bean instanceof ApplicationListener) {
1478-
// potentially not detected as a listener by getBeanNamesForType retrieval
1479-
Boolean flag = this.singletonNames.get(beanName);
1480-
if (Boolean.TRUE.equals(flag)) {
1481-
// singleton bean (top-level or inner): register on the fly
1482-
addApplicationListener((ApplicationListener<?>) bean);
1483-
}
1484-
else if (flag == null) {
1485-
if (logger.isWarnEnabled() && !containsBean(beanName)) {
1486-
// inner bean with other scope - can't reliably process events
1487-
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
1488-
"but is not reachable for event multicasting by its containing ApplicationContext " +
1489-
"because it does not have singleton scope. Only top-level listener beans are allowed " +
1490-
"to be of non-singleton scope.");
1491-
}
1492-
this.singletonNames.put(beanName, Boolean.FALSE);
1493-
}
1494-
}
1495-
return bean;
1496-
}
1497-
}
1498-
14991246
}

0 commit comments

Comments
 (0)