如何正确地重载Spring bean配置

时间:2016-11-22 09:16:55

标签: java spring

我有两个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工厂配置设置为具有某些客户端特定的内容?

6 个答案:

答案 0 :(得分:2)

就个人而言,我永远不会在春天覆盖一个豆!我看到人们花太多时间调试与此相关的问题。出于同样的原因,我永远不会使用@Primary。

在这种情况下,我会有3个上下文

  1. 包含父上下文特有的bean的上下文
  2. 包含子上下文特有的bean的上下文
  3. 包含所有共享bean的抽象上下文。
  4. 这样您就可以指定要加载的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");
    }

}

现在通过添加

运行特定的配置文件
  • 应用程序主要方法
  • 上的@ActiveProfiles(“base”)
  • spring.profiles.active = application.properties中的基本条目
  • 甚至将个人资料名称传递给jvm params

答案 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 + "'}";
        }
    }
}