Browse Source

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
pull/28987/head
Juergen Hoeller 2 years ago
parent
commit
427e5f5899
  1. 8
      spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableListableBeanFactory.java
  2. 2
      spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
  3. 4
      spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
  4. 1
      spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
  5. 11
      spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
  6. 23
      spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java
  7. 4
      spring-context/src/main/java/org/springframework/context/support/PostProcessorRegistrationDelegate.java

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2022 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.
@ -137,7 +137,10 @@ public interface ConfigurableListableBeanFactory @@ -137,7 +137,10 @@ public interface ConfigurableListableBeanFactory
/**
* Freeze all bean definitions, signalling that the registered bean definitions
* will not be modified or post-processed any further.
* <p>This allows the factory to aggressively cache bean definition metadata.
* <p>This allows the factory to aggressively cache bean definition metadata
* going forward, after clearing the initial temporary metadata cache.
* @see #clearMetadataCache()
* @see #isConfigurationFrozen()
*/
void freezeConfiguration();
@ -145,6 +148,7 @@ public interface ConfigurableListableBeanFactory @@ -145,6 +148,7 @@ public interface ConfigurableListableBeanFactory
* Return whether this factory's bean definitions are frozen,
* i.e. are not supposed to be modified or post-processed any further.
* @return {@code true} if the factory's configuration is considered frozen
* @see #freezeConfiguration()
*/
boolean isConfigurationFrozen();

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

@ -576,7 +576,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -576,7 +576,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
mbd.markAsPostProcessed();
}
}

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

@ -1700,12 +1700,12 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp @@ -1700,12 +1700,12 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
protected void markBeanAsCreated(String beanName) {
if (!this.alreadyCreated.contains(beanName)) {
synchronized (this.mergedBeanDefinitions) {
if (!this.alreadyCreated.contains(beanName)) {
if (!isBeanEligibleForMetadataCaching(beanName)) {
// Let the bean definition get re-merged now that we're actually creating
// the bean... just in case some of its metadata changed in the meantime.
clearMergedBeanDefinition(beanName);
this.alreadyCreated.add(beanName);
}
this.alreadyCreated.add(beanName);
}
}
}

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

@ -887,6 +887,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -887,6 +887,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
public void freezeConfiguration() {
clearMetadataCache();
this.configurationFrozen = true;
this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}

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

@ -439,6 +439,17 @@ public class RootBeanDefinition extends AbstractBeanDefinition { @@ -439,6 +439,17 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
}
}
/**
* Mark this bean definition as post-processed,
* i.e. processed by {@link MergedBeanDefinitionPostProcessor}.
* @since 6.0
*/
public void markAsPostProcessed() {
synchronized (this.postProcessingLock) {
this.postProcessed = true;
}
}
/**
* Register an externally managed configuration method or field.
*/

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

@ -772,6 +772,29 @@ class DefaultListableBeanFactoryTests { @@ -772,6 +772,29 @@ class DefaultListableBeanFactoryTests {
assertThat(factory.getType("child")).isEqualTo(DerivedTestBean.class);
}
@Test
void mergedBeanDefinitionChangesRetainedAfterFreezeConfiguration() {
RootBeanDefinition parentDefinition = new RootBeanDefinition(Object.class);
ChildBeanDefinition childDefinition = new ChildBeanDefinition("parent");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition("parent", parentDefinition);
factory.registerBeanDefinition("child", childDefinition);
assertThat(factory.getType("parent")).isEqualTo(Object.class);
assertThat(factory.getType("child")).isEqualTo(Object.class);
((RootBeanDefinition) factory.getBeanDefinition("parent")).setBeanClass(TestBean.class);
factory.freezeConfiguration();
assertThat(factory.getType("parent")).isEqualTo(TestBean.class);
assertThat(factory.getType("child")).isEqualTo(TestBean.class);
((RootBeanDefinition) factory.getMergedBeanDefinition("child")).setBeanClass(DerivedTestBean.class);
assertThat(factory.getBean("parent")).isInstanceOf(TestBean.class);
assertThat(factory.getBean("child")).isInstanceOf(DerivedTestBean.class);
}
@Test
void nameAlreadyBound() {
Properties p = new Properties();

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

@ -423,6 +423,7 @@ final class PostProcessorRegistrationDelegate { @@ -423,6 +423,7 @@ final class PostProcessorRegistrationDelegate {
}
}
private static final class MergedBeanDefinitionPostProcessorInvoker {
private final DefaultListableBeanFactory beanFactory;
@ -438,12 +439,14 @@ final class PostProcessorRegistrationDelegate { @@ -438,12 +439,14 @@ final class PostProcessorRegistrationDelegate {
RootBeanDefinition bd = (RootBeanDefinition) this.beanFactory.getMergedBeanDefinition(beanName);
Class<?> beanType = resolveBeanType(bd);
postProcessRootBeanDefinition(postProcessors, beanName, beanType, bd);
bd.markAsPostProcessed();
}
registerBeanPostProcessors(this.beanFactory, postProcessors);
}
private void postProcessRootBeanDefinition(List<MergedBeanDefinitionPostProcessor> postProcessors,
String beanName, Class<?> beanType, RootBeanDefinition bd) {
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, bd);
postProcessors.forEach(postProcessor -> postProcessor.postProcessMergedBeanDefinition(bd, beanType, beanName));
for (PropertyValue propertyValue : bd.getPropertyValues().getPropertyValueList()) {
@ -466,6 +469,7 @@ final class PostProcessorRegistrationDelegate { @@ -466,6 +469,7 @@ final class PostProcessorRegistrationDelegate {
private void resolveInnerBeanDefinition(BeanDefinitionValueResolver valueResolver, BeanDefinition innerBeanDefinition,
BiConsumer<String, RootBeanDefinition> resolver) {
valueResolver.resolveInnerBean(null, innerBeanDefinition, (name, rbd) -> {
resolver.accept(name, rbd);
return Void.class;

Loading…
Cancel
Save