我有两个spring(4.2)java配置,一个在基本模块中,另一个在客户端特定模块中:
@Configuration
public class BaseConfig {
@Bean
public A getA() {
return new A("aaa");
}
}
@Configuration
public class ClientConfig {
@Bean
public A getA() {
return new A("bbbb");
}
}
在app加载期间,始终会调用BaseConfig.getA()
,如何将基本bean工厂配置设置为具有某些客户端特定的内容?
答案 0 :(得分:2)
就个人而言,我永远不会在春天覆盖一个豆!我看到人们花太多时间调试与此相关的问题。出于同样的原因,我永远不会使用@Primary。
在这种情况下,我会有3个上下文
这样您就可以指定要加载的2个上下文。这可以以编程方式或使用配置文件来完成。可能你需要更多的上下文,因为你可能希望你的一些bean在测试中有所不同。
答案 1 :(得分:1)
我认为你应该看看@Profile注释。您可以简单地将配置拆分为不同的基础和客户端特定的类似:
@Configuration
@Profile("base")
public class BaseConfig {
@Bean
public A getA() {
return new A("aaa");
}
}
@Configuration
@Profile("client")
public class ClientConfig {
@Bean
public A getA() {
return new A("bbbb");
}
}
现在通过添加
运行特定的配置文件答案 2 :(得分:0)
我不确定如何扩展bean配置类。一种解决方案是使用@Primary注释在ClientConfig
中标记bean。这将导致使用Bean A的ClientConfig定义。
答案 3 :(得分:0)
如果您同时包含这两种配置,则可以查看主要注释:Primary
表示当多个候选者有资格自动装配单值依赖项时,应优先考虑bean。如果只是一个主要的' bean存在于候选者中,它将是自动装配的值。
答案 4 :(得分:0)
@Profile Annotation可以用于此...
@Configuration
@Profile("base")
public class BaseConfig {
@Bean
public A getA() {
return new A("aaa");
}
}
@Configuration
@Profile("client")
public class ClientConfig {
@Bean
public A getA() {
return new A("bbbb");
}
}
使用以下链接 https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile/
答案 5 :(得分:0)
这是对上述评论的回答,但由于评论的格式和大小有限,我会回答一个答案。
spring如何在加载配置文件时定义bean的排序和覆盖
这取决于加载多个配置的含义。如果你有一个spring上下文并且有两个带有@Configuration的类并进行组件扫描,那么Spring将构建依赖树,并且最后加载的上下文(bean)将定义bean(因为它会覆盖第一个定义)。
如果父子关系中有多个Spring上下文,那么子项并查看父bean,如果使用child.getBean(type.class),也将“覆盖”父bean。父母无法看到孩子们的豆子。
使用@Primary。如果你有一个Spring上下文(可以来自多个配置)来定义两个相同类型的bean,你将无法使用context.getBean(type.class)或@AutoWired(没有@Qualifier),因为你有多个bean相同类型。如果其中一个bean是@Primary,则可以更改此行为。我试图避免在我自己的代码中使用@Primary,但我可以看到它在Spring boots自动配置系统中大量使用,所以我认为它在框架设计方面有一些微妙的用法。
这是一个小例子,请注意,如果直接加载配置类,则不需要@Configuration注释。
public class ParentChildContext {
public static void main(String[] args) {
parentChildContext();
twoConfigurationsSameContext();
}
private static void twoConfigurationsSameContext() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(Parent.class, Child.class);
// if you have two beans of the same type in a context they can be loaded by name
Object childA = ctx.getBean("childA");
System.out.println("childA = " + childA);
Object parentA = ctx.getBean("parentA");
System.out.println("parentA = " + parentA);
// since both configurations define A, you can't do this
ctx.getBean(A.class);
}
private static void parentChildContext() {
ApplicationContext parentCtx = new AnnotationConfigApplicationContext(Parent.class);
A parentA = parentCtx.getBean(A.class);
System.out.println("parent = " + parentA);
AnnotationConfigApplicationContext childCtx = new AnnotationConfigApplicationContext();
childCtx.register(Child.class);
childCtx.setParent(parentCtx);
childCtx.refresh();
A childA = childCtx.getBean(A.class);
System.out.println("child = " + childA);
}
public static class Parent {
@Bean
//@Primary // if you enable @Primary parent bean will override child unless the context is hierarchical
public A parentA() {
return new A("parent");
}
}
public static class Child {
@Bean
public A childA() {
return new A("child");
}
}
public static class A {
private final String s;
public A(String s) {
this.s = s;
}
@Override
public String toString() {
return "A{s='" + s + "'}";
}
}
}