spring boot starter注入基于属性的bean

时间:2017-02-28 08:57:05

标签: java spring spring-boot

最近,我正在开发一个为客户端代码提供ServiceA的spring boot starter。我想提供配置属性:

my.namespace.serviceA=impl1    #or other implemtations

my.namespace.serviceA.impl1.prop1=ServiceAImpl1Prop1Val
my.namespace.serviceA.impl1.prop2=ServiceAImpl1Prop2Val
# some other properties of ServiceA

我还为@ConfigurationProperties的不同实现添加了几个注释为ServiceA的Bean类,因为springboot会自动将这些属性加载到这些bean中。

我的初学者希望为客户端代码提供ServiceA的接口,以便它可以用作:

@Autowire
private ServiceA serviceA;

我需要提供一个工厂方法,如:

@Bean
public ServiceA serviceA() {
    //TODO load my.namespace.serviceA and create the corresponding 
    //instance of ServiceA Implementation with given properties
}

由于属性根据不同的实现而变化,是否有一种优雅的方法来实现这种工厂方法利用@ConfigurationProperties的属性bean?

1 个答案:

答案 0 :(得分:3)

从表面上看,你的答案是90%。

您可以将ServiceA标记为组件,而不是手动创建bean,而Spring组件扫描将为您创建bean。

查看ServiceA的实现

@ConfigurationProperties(prefix = "my.namespace.serviceA.impl1")
@Component
public ConcreteA implements ServiceA {
    private String prop1;
    private String prop2;
}

修改

根据您想要一个ServiceA实例的事实,您仍然需要使用@ConfigurationProperties为您的班级添加注释,但请移除@Component

@ConfigurationProperties(prefix = "my.namespace.serviceA.impl1")
public ConcreteA implements ServiceA {
    private String prop1;
    public void setProp1(String s) {
        prop1 = s;
    }
}

您必须至少拥有属性的设置者。

然后在你创建bean的config类中

@ConfigurationProperties(prefix = "my.namespace")
@Configuration
public SomeConfig {
    private String serviceA;

    public void setServiceA(String s) {
        serviceA = s;
    }

    @Bean
    public ServiceA serviceA() {
        if (serviceA.equals("ConcreteA1")) {
            return new ConcreteA1();
        } else {
            return new ConcreteA2();
        }
    }
}

使用if语句的方法实际上违反了开放/封闭原则,内省是一种更好的方法,但我认为你明白了。