为了账号安全,请及时绑定邮箱和手机立即绑定

Spring boot - 在@Qualifier 上使用可配置的值

Spring boot - 在@Qualifier 上使用可配置的值

喵喵时光机 2023-05-17 17:02:54
我有一个接口的两个实现,我想根据配置选择要使用的实现。限定符解决方案不起作用,因为它是在配置之前初始化的。我怎样才能做到这一点?我收到了你的评论:我有两个不同的作业实现,并且可以每月更改类型,因此如果可配置,则可以减少部署和代码更改。你可能有这样的事情: interface Job {     void foo(); } class JobA implements Job {     void foo() {...} } class JobB implements Job {     void foo() {...} } class JobExecutor {        Job job;    // autowired constructor    public JobExecutor(Job job) {this.job = job;} }而且,如果我没听错的话,在同一个应用程序上下文中同时加载两个 bean 是没有意义的。但如果是这样,则@Qualifier不是适合这项工作的工具。我建议改用集成到 spring boot 中的条件:@Configurationpublic class MyConfiguration {    @ConditionalOnProperty(name = "job.name", havingValue = "jobA")    @Bean     public Job jobA() {         return new JobA();    }    @ConditionalOnProperty(name = "job.name", havingValue = "jobB")    @Bean     public Job jobB() {         return new JobB();    }    @Bean    public JobExecutor jobExecutor(Job job) {       return new JobExecutor(job);    }}现在在application.properties(或任何你拥有的 yaml)中定义: job.name = jobA # or jobB当然,jobA/jobB您可能会使用来自您的业务领域的更多不言自明的名称来代替。
查看完整描述

4 回答

?
慕盖茨4494581

TA贡献1850条经验 获得超11个赞

我有两个不同的作业实现,并且可以每月更改类型,因此如果可配置,则可以减少部署和代码更改。


你可能有这样的事情:


 interface Job {

     void foo();

 }


 class JobA implements Job {

     void foo() {...}

 }


 class JobB implements Job {

     void foo() {...}

 }


 class JobExecutor {

    

    Job job;

    // autowired constructor

    public JobExecutor(Job job) {this.job = job;}

 }

而且,如果我没听错的话,在同一个应用程序上下文中同时加载两个 bean 是没有意义的。


但如果是这样,则@Qualifier不是适合这项工作的工具。


我建议改用集成到 spring boot 中的条件:


@Configuration

public class MyConfiguration {


    @ConditionalOnProperty(name = "job.name", havingValue = "jobA")

    @Bean 

    public Job jobA() {

         return new JobA();

    }


    @ConditionalOnProperty(name = "job.name", havingValue = "jobB")

    @Bean 

    public Job jobB() {

         return new JobB();

    }

    @Bean

    public JobExecutor jobExecutor(Job job) {

       return new JobExecutor(job);

    }

}

现在在application.properties(或任何你拥有的 yaml)中定义:


 job.name = jobA # or jobB

当然,jobA/jobB您可能会使用来自您的业务领域的更多不言自明的名称来代替。


查看完整回答
反对 回复 2023-05-17
?
慕尼黑的夜晚无繁华

TA贡献1864条经验 获得超6个赞

如果您稍微摆弄一下基于 Spring java 的配置,您可以使用它来完成它,您可以在其中根据配置值以编程方式决定正确的实现:


@Configuration

public class MyAppContext implements EnvironmentAware{


    private Environment env;


    @Override

    public void setEnvironment(final Environment env) {

       this.env = env;

    }


    @Bean

    public MyBeanByConfig myBeanByConfig(){

        String configValue = env.getProperty("mybean.config");


        if(configValue.equals("1")){

           return new MyBeanByConfigOne();

        }else{

           return new MyBeanByConfigTwo();

        }

    }

}

在限定符上你会放:


@Qualifier("myBeanByConfig")

您可能还需要在配置类上添加@ComponentScan和。@PropertySource


查看完整回答
反对 回复 2023-05-17
?
蝴蝶刀刀

TA贡献1801条经验 获得超8个赞

假设您有一个界面:


public interface Foo {

    void doSomething();

}

和2个实现:


public class Foo_A implements Foo {

    @Override

    doSomething() {...}

}


public class Foo_B implements Foo {

    @Override

    doSomething() {...}

}


现在您想根据属性文件中的属性值使用 Foo_A/Foo_B:


foo_name: "A"

我发现最简单的方法是:


首先,您限定您的实施


@Component("Foo_A")

public class Foo_A implements Foo {

    @Override

    doSomething() {...}

}


@Component("Foo_B")

public class Foo_B implements Foo {

    @Override

    doSomething() {...}

}


然后,无论您要在何处使用它(例如 Bar 类),您都可以只使用 @Qualifier 来指定您正在实例化的实现并使用 @Value 从属性中获取值。然后,在方法内部,通过一个简单的 if/else 语句,您可以使用属性值来决定要调用哪个实现。

public class Bar {


    @Value("${foo_name}")

    private String fooName;


    @Qualifier("Foo_A")

    private Foo fooA;


    @Qualifier("Foo_B")

    private Foo fooB;


    public void doSomething() {

        if (fooName.equals("A")) {

            fooA.doSomething();

        } else {

            fooB.doSomething();

        }

    }


}


查看完整回答
反对 回复 2023-05-17
?
神不在的星期二

TA贡献1963条经验 获得超6个赞

我最终将两个自动装配的实现添加到主应用程序类,然后为每个实现定义一个 bean:


@Autowired

TypeOneImpl typeOneImpl

@Bean(name = "typeOneImpl")

public InterfaceRClass getTypeOneImpl()

{

    return typeOneImpl;

}

然后在另一个类中我定义了一个配置字段


@Value("${myClass.type}")

private String configClassType;

// the below should be defined in constructor

private final InterfaceRClass interfaceRClassElement ;

并使用 @Autowired 注释为其添加了一个 setter:


@Autowired

public void setMyClassType(ApplicationContext context) {

    interfaceRClassElement = (InterfaceRClass) context.getBean(configClassType);

}

在配置中,该值应为 typeOneImpl(添加 typeTwoImpl 用于附加实现)


查看完整回答
反对 回复 2023-05-17
  • 4 回答
  • 0 关注
  • 294 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信