Allow @Bean method to override scanned class matching its return type
Closes gh-31052
This commit is contained in:
parent
d89e305c87
commit
57f675c537
|
|
@ -301,8 +301,12 @@ class ConfigurationClassBeanDefinitionReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
// A bean definition resulting from a component scan can be silently overridden
|
// A bean definition resulting from a component scan can be silently overridden
|
||||||
// by an @Bean method, as of 4.2...
|
// by an @Bean method - and as of 6.1, even when general overriding is disabled
|
||||||
if (existingBeanDef instanceof ScannedGenericBeanDefinition) {
|
// as long as the bean class is the same.
|
||||||
|
if (existingBeanDef instanceof ScannedGenericBeanDefinition scannedBeanDef) {
|
||||||
|
if (beanMethod.getMetadata().getReturnTypeName().equals(scannedBeanDef.getBeanClassName())) {
|
||||||
|
this.registry.removeBeanDefinition(beanName);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.context.annotation;
|
package org.springframework.context.annotation;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
@ -209,7 +208,7 @@ class ComponentScanAnnotationIntegrationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void withScopedProxyThroughRegex() throws IOException, ClassNotFoundException {
|
void withScopedProxyThroughRegex() {
|
||||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
ctx.register(ComponentScanWithScopedProxyThroughRegex.class);
|
ctx.register(ComponentScanWithScopedProxyThroughRegex.class);
|
||||||
ctx.getBeanFactory().registerScope("myScope", new SimpleMapScope());
|
ctx.getBeanFactory().registerScope("myScope", new SimpleMapScope());
|
||||||
|
|
@ -221,7 +220,7 @@ class ComponentScanAnnotationIntegrationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void withScopedProxyThroughAspectJPattern() throws IOException, ClassNotFoundException {
|
void withScopedProxyThroughAspectJPattern() {
|
||||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
ctx.register(ComponentScanWithScopedProxyThroughAspectJPattern.class);
|
ctx.register(ComponentScanWithScopedProxyThroughAspectJPattern.class);
|
||||||
ctx.getBeanFactory().registerScope("myScope", new SimpleMapScope());
|
ctx.getBeanFactory().registerScope("myScope", new SimpleMapScope());
|
||||||
|
|
@ -233,7 +232,7 @@ class ComponentScanAnnotationIntegrationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void withMultipleAnnotationIncludeFilters1() throws IOException, ClassNotFoundException {
|
void withMultipleAnnotationIncludeFilters1() {
|
||||||
AnnotationConfigApplicationContext ctx =
|
AnnotationConfigApplicationContext ctx =
|
||||||
new AnnotationConfigApplicationContext(ComponentScanWithMultipleAnnotationIncludeFilters1.class);
|
new AnnotationConfigApplicationContext(ComponentScanWithMultipleAnnotationIncludeFilters1.class);
|
||||||
ctx.getBean(DefaultNamedComponent.class); // @CustomStereotype-annotated
|
ctx.getBean(DefaultNamedComponent.class); // @CustomStereotype-annotated
|
||||||
|
|
@ -241,13 +240,30 @@ class ComponentScanAnnotationIntegrationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void withMultipleAnnotationIncludeFilters2() throws IOException, ClassNotFoundException {
|
void withMultipleAnnotationIncludeFilters2() {
|
||||||
AnnotationConfigApplicationContext ctx =
|
AnnotationConfigApplicationContext ctx =
|
||||||
new AnnotationConfigApplicationContext(ComponentScanWithMultipleAnnotationIncludeFilters2.class);
|
new AnnotationConfigApplicationContext(ComponentScanWithMultipleAnnotationIncludeFilters2.class);
|
||||||
ctx.getBean(DefaultNamedComponent.class); // @CustomStereotype-annotated
|
ctx.getBean(DefaultNamedComponent.class); // @CustomStereotype-annotated
|
||||||
ctx.getBean(MessageBean.class); // @CustomComponent-annotated
|
ctx.getBean(MessageBean.class); // @CustomComponent-annotated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void withBeanMethodOverride() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(ComponentScanWithMultipleAnnotationIncludeFilters3.class);
|
||||||
|
ctx.refresh();
|
||||||
|
assertThat(ctx.getBean(DefaultNamedComponent.class).toString()).isEqualTo("overridden");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void withBeanMethodOverrideAndGeneralOverridingDisabled() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.getDefaultListableBeanFactory().setAllowBeanDefinitionOverriding(false);
|
||||||
|
ctx.register(ComponentScanWithMultipleAnnotationIncludeFilters3.class);
|
||||||
|
ctx.refresh();
|
||||||
|
assertThat(ctx.getBean(DefaultNamedComponent.class).toString()).isEqualTo("overridden");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void withBasePackagesAndValueAlias() {
|
void withBasePackagesAndValueAlias() {
|
||||||
AnnotationConfigApplicationContext ctx =
|
AnnotationConfigApplicationContext ctx =
|
||||||
|
|
@ -292,6 +308,7 @@ class ComponentScanAnnotationIntegrationTests {
|
||||||
static class MultipleComposedAnnotationsConfig {
|
static class MultipleComposedAnnotationsConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static class AwareTypeFilter implements TypeFilter, EnvironmentAware,
|
static class AwareTypeFilter implements TypeFilter, EnvironmentAware,
|
||||||
ResourceLoaderAware, BeanClassLoaderAware, BeanFactoryAware {
|
ResourceLoaderAware, BeanClassLoaderAware, BeanFactoryAware {
|
||||||
|
|
||||||
|
|
@ -329,10 +346,8 @@ class ComponentScanAnnotationIntegrationTests {
|
||||||
assertThat(this.environment).isNotNull();
|
assertThat(this.environment).isNotNull();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -461,11 +476,27 @@ class ComponentScanWithMultipleAnnotationIncludeFilters1 {}
|
||||||
)
|
)
|
||||||
class ComponentScanWithMultipleAnnotationIncludeFilters2 {}
|
class ComponentScanWithMultipleAnnotationIncludeFilters2 {}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan(basePackages = "example.scannable",
|
||||||
|
useDefaultFilters = false,
|
||||||
|
includeFilters = @Filter({CustomStereotype.class, CustomComponent.class})
|
||||||
|
)
|
||||||
|
class ComponentScanWithMultipleAnnotationIncludeFilters3 {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DefaultNamedComponent thoreau() {
|
||||||
|
return new DefaultNamedComponent() {
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "overridden";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(
|
@ComponentScan(
|
||||||
value = "example.scannable",
|
value = "example.scannable",
|
||||||
basePackages = "example.scannable",
|
basePackages = "example.scannable",
|
||||||
basePackageClasses = example.scannable.PackageMarker.class)
|
basePackageClasses = example.scannable.PackageMarker.class)
|
||||||
class ComponentScanWithBasePackagesAndValueAlias {}
|
class ComponentScanWithBasePackagesAndValueAlias {}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue