SpringJava配置扩展抽象配置
在我们的软件中,我们使用SpringJava配置。我们有一个设置,其中一个配置扩展了一个抽象配置。请看一下这个测试用例:
import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; public class SpringConfigTest { @Test public void test() { final AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class); ctx.getBeansOfType(AtomicInteger.class).entrySet().stream().forEach( b -> System.out.println(b.getKey() + " : " + b.getValue() + " (" + b.getValue().hashCode() + ")")); } @Configuration public static class MyConfig extends AbstractConfig { @Bean(name = "anotherName") public AtomicInteger myBean() { return new AtomicInteger(5); } } public static abstract class AbstractConfig { @Bean public AtomicInteger myBean() { return new AtomicInteger(10); } } }
其思想是MyConfig
覆盖AbstractConfig
,并且在创建的ApplicationContext中只有一个名为anotherName
的类型为AtomicInteger
的bean
结果是:
anotherName : 5 (2109798150) myBean : 5 (1074389766)
所以它说,有两个bean(两个实例,每个名称一个),更令人惊讶的是,使用相同的方法(MyConfig#myBean()
)创建了这两个bean
这种行为在我们看来很奇怪:我们期望spring要么尊重java的常规继承方式,要么只从MyConfig
创建bean。。。或者至少创建两个独立的bean(“10”和“5”),以防它将AbstractConfig
视为独立的配置
在研究此问题时,我们还尝试在MyConfig
类上注册方法名:
public static class MyConfig extends AbstractConfig { @Bean(name = ["anotherName", "myBean"]) public AtomicInteger myBean() { ...
这次我们只有一个豆子:
anotherName : 5 (2109798150)
。。更让我们惊讶的是
有人知道这是正确的行为还是我们只是用错了?我们应该在春天的吉拉举行一场音乐会吗? 提前谢谢
# 1 楼答案
在春季,bean可以先按类型连接,然后按名称连接。 因此@Qualifier(“myBeanName”)可以消除自动连接多个具有相同类型的bean的歧义,例如
因此: 非抽象bean被赋予了另一个名称,这使得它在应用程序上下文中被视为不同的bean
您可以在非配置类中声明bean。这称为“lite”模式,但在应用程序上下文中它仍然是一个bean。 另请参见thislite模式的答案
我不知道可以给一个bean多个名称,但是由于Springbean在默认情况下是单例的,所以在第二种情况下,应该只创建一个bean,因为“myBean”已经存在,并且应用程序上下文中只能有一个具有该名称的bean
# 2 楼答案
我不是Spring专业人士,但我要说,这种行为是出于设计。为了实现您想要的(我希望我猜对了)“注入这个bean而不是另一个”,您将在bean上使用@Primary,根据您将使用@Conditional即@Profile的情况有选择地启用配置