Skip to content

Commit 427e5f5

Browse files
committed
Final merged bean definition clearing in freezeConfiguration
Instead of individual last-minute clearing in markBeanAsCreated, the factory clears all merged bean definitions in freezeConfiguration, retaining the changes of merged bean definition post-processing after that point (in particular in refreshForAotProcessing). Closes gh-28948
1 parent 7c91776 commit 427e5f5

File tree

7 files changed

+48
-5
lines changed

7 files changed

+48
-5
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableListableBeanFactory.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -137,14 +137,18 @@ boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)
137137
/**
138138
* Freeze all bean definitions, signalling that the registered bean definitions
139139
* will not be modified or post-processed any further.
140-
* <p>This allows the factory to aggressively cache bean definition metadata.
140+
* <p>This allows the factory to aggressively cache bean definition metadata
141+
* going forward, after clearing the initial temporary metadata cache.
142+
* @see #clearMetadataCache()
143+
* @see #isConfigurationFrozen()
141144
*/
142145
void freezeConfiguration();
143146

144147
/**
145148
* Return whether this factory's bean definitions are frozen,
146149
* i.e. are not supposed to be modified or post-processed any further.
147150
* @return {@code true} if the factory's configuration is considered frozen
151+
* @see #freezeConfiguration()
148152
*/
149153
boolean isConfigurationFrozen();
150154

spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable
576576
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
577577
"Post-processing of merged bean definition failed", ex);
578578
}
579-
mbd.postProcessed = true;
579+
mbd.markAsPostProcessed();
580580
}
581581
}
582582

spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,12 +1700,12 @@ ResolvableType getTypeForFactoryBeanFromAttributes(AttributeAccessor attributes)
17001700
protected void markBeanAsCreated(String beanName) {
17011701
if (!this.alreadyCreated.contains(beanName)) {
17021702
synchronized (this.mergedBeanDefinitions) {
1703-
if (!this.alreadyCreated.contains(beanName)) {
1703+
if (!isBeanEligibleForMetadataCaching(beanName)) {
17041704
// Let the bean definition get re-merged now that we're actually creating
17051705
// the bean... just in case some of its metadata changed in the meantime.
17061706
clearMergedBeanDefinition(beanName);
1707-
this.alreadyCreated.add(beanName);
17081707
}
1708+
this.alreadyCreated.add(beanName);
17091709
}
17101710
}
17111711
}

spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,7 @@ public void clearMetadataCache() {
887887

888888
@Override
889889
public void freezeConfiguration() {
890+
clearMetadataCache();
890891
this.configurationFrozen = true;
891892
this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
892893
}

spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,17 @@ public void setInstanceSupplier(@Nullable Supplier<?> instanceSupplier) {
439439
}
440440
}
441441

442+
/**
443+
* Mark this bean definition as post-processed,
444+
* i.e. processed by {@link MergedBeanDefinitionPostProcessor}.
445+
* @since 6.0
446+
*/
447+
public void markAsPostProcessed() {
448+
synchronized (this.postProcessingLock) {
449+
this.postProcessed = true;
450+
}
451+
}
452+
442453
/**
443454
* Register an externally managed configuration method or field.
444455
*/

spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,29 @@ void getTypeWorksAfterParentChildMerging() {
772772
assertThat(factory.getType("child")).isEqualTo(DerivedTestBean.class);
773773
}
774774

775+
@Test
776+
void mergedBeanDefinitionChangesRetainedAfterFreezeConfiguration() {
777+
RootBeanDefinition parentDefinition = new RootBeanDefinition(Object.class);
778+
ChildBeanDefinition childDefinition = new ChildBeanDefinition("parent");
779+
780+
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
781+
factory.registerBeanDefinition("parent", parentDefinition);
782+
factory.registerBeanDefinition("child", childDefinition);
783+
784+
assertThat(factory.getType("parent")).isEqualTo(Object.class);
785+
assertThat(factory.getType("child")).isEqualTo(Object.class);
786+
((RootBeanDefinition) factory.getBeanDefinition("parent")).setBeanClass(TestBean.class);
787+
788+
factory.freezeConfiguration();
789+
790+
assertThat(factory.getType("parent")).isEqualTo(TestBean.class);
791+
assertThat(factory.getType("child")).isEqualTo(TestBean.class);
792+
((RootBeanDefinition) factory.getMergedBeanDefinition("child")).setBeanClass(DerivedTestBean.class);
793+
794+
assertThat(factory.getBean("parent")).isInstanceOf(TestBean.class);
795+
assertThat(factory.getBean("child")).isInstanceOf(DerivedTestBean.class);
796+
}
797+
775798
@Test
776799
void nameAlreadyBound() {
777800
Properties p = new Properties();

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ private boolean isInfrastructureBean(@Nullable String beanName) {
423423
}
424424
}
425425

426+
426427
private static final class MergedBeanDefinitionPostProcessorInvoker {
427428

428429
private final DefaultListableBeanFactory beanFactory;
@@ -438,12 +439,14 @@ private void invokeMergedBeanDefinitionPostProcessors() {
438439
RootBeanDefinition bd = (RootBeanDefinition) this.beanFactory.getMergedBeanDefinition(beanName);
439440
Class<?> beanType = resolveBeanType(bd);
440441
postProcessRootBeanDefinition(postProcessors, beanName, beanType, bd);
442+
bd.markAsPostProcessed();
441443
}
442444
registerBeanPostProcessors(this.beanFactory, postProcessors);
443445
}
444446

445447
private void postProcessRootBeanDefinition(List<MergedBeanDefinitionPostProcessor> postProcessors,
446448
String beanName, Class<?> beanType, RootBeanDefinition bd) {
449+
447450
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, bd);
448451
postProcessors.forEach(postProcessor -> postProcessor.postProcessMergedBeanDefinition(bd, beanType, beanName));
449452
for (PropertyValue propertyValue : bd.getPropertyValues().getPropertyValueList()) {
@@ -466,6 +469,7 @@ private void postProcessRootBeanDefinition(List<MergedBeanDefinitionPostProcesso
466469

467470
private void resolveInnerBeanDefinition(BeanDefinitionValueResolver valueResolver, BeanDefinition innerBeanDefinition,
468471
BiConsumer<String, RootBeanDefinition> resolver) {
472+
469473
valueResolver.resolveInnerBean(null, innerBeanDefinition, (name, rbd) -> {
470474
resolver.accept(name, rbd);
471475
return Void.class;

0 commit comments

Comments
 (0)