Reverse engineer documentation for Bean Override internals
This commit is contained in:
parent
ded5c13e19
commit
c3ff6cf319
|
|
@ -104,19 +104,6 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy certain details of a {@link BeanDefinition} to the definition created by
|
|
||||||
* this processor for a given {@link OverrideMetadata}.
|
|
||||||
* <p>The default implementation copies the {@linkplain BeanDefinition#isPrimary()
|
|
||||||
* primary flag}, @{@linkplain BeanDefinition#isFallback() fallback flag}
|
|
||||||
* and the {@linkplain BeanDefinition#getScope() scope}.
|
|
||||||
*/
|
|
||||||
protected void copyBeanDefinitionDetails(BeanDefinition from, RootBeanDefinition to) {
|
|
||||||
to.setPrimary(from.isPrimary());
|
|
||||||
to.setFallback(from.isFallback());
|
|
||||||
to.setScope(from.getScope());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerBeanOverride(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry,
|
private void registerBeanOverride(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry,
|
||||||
OverrideMetadata overrideMetadata) {
|
OverrideMetadata overrideMetadata) {
|
||||||
|
|
||||||
|
|
@ -132,6 +119,8 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
|
||||||
private void registerReplaceDefinition(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry,
|
private void registerReplaceDefinition(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry,
|
||||||
OverrideMetadata overrideMetadata, boolean enforceExistingDefinition) {
|
OverrideMetadata overrideMetadata, boolean enforceExistingDefinition) {
|
||||||
|
|
||||||
|
// The following is a "dummy" bean definition which should not be used to
|
||||||
|
// create an actual bean instance.
|
||||||
RootBeanDefinition beanDefinition = createBeanDefinition(overrideMetadata);
|
RootBeanDefinition beanDefinition = createBeanDefinition(overrideMetadata);
|
||||||
String beanName = overrideMetadata.getBeanName();
|
String beanName = overrideMetadata.getBeanName();
|
||||||
String beanNameIncludingFactory;
|
String beanNameIncludingFactory;
|
||||||
|
|
@ -157,22 +146,27 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
|
||||||
beanNameIncludingFactory = beanName;
|
beanNameIncludingFactory = beanName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process existing bean definition.
|
||||||
if (existingBeanDefinition != null) {
|
if (existingBeanDefinition != null) {
|
||||||
copyBeanDefinitionDetails(existingBeanDefinition, beanDefinition);
|
copyBeanDefinitionProperties(existingBeanDefinition, beanDefinition);
|
||||||
registry.removeBeanDefinition(beanName);
|
registry.removeBeanDefinition(beanName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// At this point, we either removed an existing bean definition above, or
|
||||||
|
// there was no bean definition to begin with. So, we register the dummy bean
|
||||||
|
// definition to ensure that a bean definition exists for the given bean name.
|
||||||
registry.registerBeanDefinition(beanName, beanDefinition);
|
registry.registerBeanDefinition(beanName, beanDefinition);
|
||||||
|
|
||||||
Object override = overrideMetadata.createOverride(beanName, existingBeanDefinition, null);
|
Object override = overrideMetadata.createOverride(beanName, existingBeanDefinition, null);
|
||||||
if (beanFactory.isSingleton(beanNameIncludingFactory)) {
|
|
||||||
// Now we have an instance (the override) that we can register.
|
|
||||||
// At this stage we don't expect a singleton instance to be present,
|
|
||||||
// and this call will throw if there is such an instance already.
|
|
||||||
beanFactory.registerSingleton(beanName, override);
|
|
||||||
}
|
|
||||||
|
|
||||||
overrideMetadata.track(override, beanFactory);
|
overrideMetadata.track(override, beanFactory);
|
||||||
this.overrideRegistrar.registerNameForMetadata(overrideMetadata, beanNameIncludingFactory);
|
this.overrideRegistrar.registerNameForMetadata(overrideMetadata, beanNameIncludingFactory);
|
||||||
|
|
||||||
|
if (beanFactory.isSingleton(beanNameIncludingFactory)) {
|
||||||
|
// Now we have an instance (the override) that we can register. At this
|
||||||
|
// stage we don't expect a singleton instance to be present, and this call
|
||||||
|
// will throw an exception if there is such an instance already.
|
||||||
|
beanFactory.registerSingleton(beanName, override);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getBeanNameForType(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry,
|
private String getBeanNameForType(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry,
|
||||||
|
|
@ -231,13 +225,6 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
|
||||||
this.overrideRegistrar.registerNameForMetadata(metadata, beanName);
|
this.overrideRegistrar.registerNameForMetadata(metadata, beanName);
|
||||||
}
|
}
|
||||||
|
|
||||||
RootBeanDefinition createBeanDefinition(OverrideMetadata metadata) {
|
|
||||||
RootBeanDefinition definition = new RootBeanDefinition(metadata.getBeanType().resolve());
|
|
||||||
definition.setTargetType(metadata.getBeanType());
|
|
||||||
definition.setQualifiedElement(metadata.getField());
|
|
||||||
return definition;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<String> getExistingBeanNamesByType(ConfigurableListableBeanFactory beanFactory, OverrideMetadata metadata,
|
private Set<String> getExistingBeanNamesByType(ConfigurableListableBeanFactory beanFactory, OverrideMetadata metadata,
|
||||||
boolean checkAutowiredCandidate) {
|
boolean checkAutowiredCandidate) {
|
||||||
|
|
||||||
|
|
@ -272,6 +259,26 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static RootBeanDefinition createBeanDefinition(OverrideMetadata metadata) {
|
||||||
|
RootBeanDefinition definition = new RootBeanDefinition(metadata.getBeanType().resolve());
|
||||||
|
definition.setTargetType(metadata.getBeanType());
|
||||||
|
definition.setQualifiedElement(metadata.getField());
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the following properties of the source {@link BeanDefinition} to the
|
||||||
|
* target: the {@linkplain BeanDefinition#isPrimary() primary flag}, the
|
||||||
|
* {@linkplain BeanDefinition#isFallback() fallback flag}, and the
|
||||||
|
* {@linkplain BeanDefinition#getScope() scope}.
|
||||||
|
*/
|
||||||
|
private static void copyBeanDefinitionProperties(BeanDefinition source, RootBeanDefinition target) {
|
||||||
|
target.setPrimary(source.isPrimary());
|
||||||
|
target.setFallback(source.isFallback());
|
||||||
|
target.setScope(source.getScope());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static class WrapEarlyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
|
static class WrapEarlyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
|
||||||
PriorityOrdered {
|
PriorityOrdered {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ import static org.mockito.Mockito.mock;
|
||||||
*
|
*
|
||||||
* @author Simon Baslé
|
* @author Simon Baslé
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
|
* @author Sam Brannen
|
||||||
*/
|
*/
|
||||||
class BeanOverrideBeanFactoryPostProcessorTests {
|
class BeanOverrideBeanFactoryPostProcessorTests {
|
||||||
|
|
||||||
|
|
@ -200,7 +201,7 @@ class BeanOverrideBeanFactoryPostProcessorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void allowReplaceDefinitionWhenSingletonDefinitionPresent() {
|
void replaceBeanByNameWithMatchingBeanDefinitionWithExplicitSingletonScope() {
|
||||||
AnnotationConfigApplicationContext context = createContext(CaseByName.class);
|
AnnotationConfigApplicationContext context = createContext(CaseByName.class);
|
||||||
RootBeanDefinition definition = new RootBeanDefinition(String.class, () -> "ORIGINAL");
|
RootBeanDefinition definition = new RootBeanDefinition(String.class, () -> "ORIGINAL");
|
||||||
definition.setScope(BeanDefinition.SCOPE_SINGLETON);
|
definition.setScope(BeanDefinition.SCOPE_SINGLETON);
|
||||||
|
|
@ -212,7 +213,7 @@ class BeanOverrideBeanFactoryPostProcessorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void copyDefinitionPrimaryFallbackAndScope() {
|
void replaceBeanByNameWithMatchingBeanDefinitionRetainsPrimaryFallbackAndScopeProperties() {
|
||||||
AnnotationConfigApplicationContext context = createContext(CaseByName.class);
|
AnnotationConfigApplicationContext context = createContext(CaseByName.class);
|
||||||
context.getBeanFactory().registerScope("customScope", new SimpleThreadScope());
|
context.getBeanFactory().registerScope("customScope", new SimpleThreadScope());
|
||||||
RootBeanDefinition definition = new RootBeanDefinition(String.class, () -> "ORIGINAL");
|
RootBeanDefinition definition = new RootBeanDefinition(String.class, () -> "ORIGINAL");
|
||||||
|
|
@ -232,22 +233,22 @@ class BeanOverrideBeanFactoryPostProcessorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void createDefinitionShouldSetQualifierElement() {
|
void qualifiedElementIsSetToBeanOverrideField() {
|
||||||
AnnotationConfigApplicationContext context = createContext(CaseByNameWithQualifier.class);
|
AnnotationConfigApplicationContext context = createContext(CaseByNameWithQualifier.class);
|
||||||
context.registerBeanDefinition("descriptionBean", new RootBeanDefinition(String.class, () -> "ORIGINAL"));
|
context.registerBeanDefinition("descriptionBean", new RootBeanDefinition(String.class, () -> "ORIGINAL"));
|
||||||
|
|
||||||
assertThatNoException().isThrownBy(context::refresh);
|
assertThatNoException().isThrownBy(context::refresh);
|
||||||
assertThat(context.getBeanDefinition("descriptionBean"))
|
assertThat(context.getBeanDefinition("descriptionBean"))
|
||||||
.isInstanceOfSatisfying(RootBeanDefinition.class, this::isTheValueField);
|
.isInstanceOfSatisfying(RootBeanDefinition.class, this::qualifiedElementIsField);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void isTheValueField(RootBeanDefinition def) {
|
private void qualifiedElementIsField(RootBeanDefinition def) {
|
||||||
assertThat(def.getQualifiedElement()).isInstanceOfSatisfying(Field.class, field -> {
|
assertThat(def.getQualifiedElement()).isInstanceOfSatisfying(Field.class,
|
||||||
assertThat(field.getDeclaringClass()).isEqualTo(CaseByNameWithQualifier.class);
|
field -> {
|
||||||
assertThat(field.getName()).as("annotated field name")
|
assertThat(field.getDeclaringClass()).isEqualTo(CaseByNameWithQualifier.class);
|
||||||
.isEqualTo("description");
|
assertThat(field.getName()).as("annotated field name").isEqualTo("description");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private AnnotationConfigApplicationContext createContext(Class<?> testClass) {
|
private AnnotationConfigApplicationContext createContext(Class<?> testClass) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue