一、问题的形容

在理论的零碎利用开发中我常常会遇到这样的一类需要,置信大家在工作中也会常常遇到:

  • 同一个零碎在多个省份部署。
  • 一个业务在北京是一种实现形式,是基于北京用户的需要。
  • 同样的业务在上海是另外一种实现形式,与北京的实现形式大同小异

遇到这样的需要,咱们通常会定义一个业务实现的接口,比方:

public interface IDemoService {  public void doSomething();}

在北京环境下这样实现,比方:

@Componentpublic class DemoServiceBeijing implements IDemoService {  @Override  public void doSomething() {System.out.println("北京的业务实现");}}

在上海环境下这样实现,比方:

@Componentpublic class DemoServiceShanghai implements IDemoService {  @Override  public void doSomething() {System.out.println("上海的业务实现");}}

而后咱们写一个模仿业务测试用例

@SpringBootTestclass DemoApplicationTests {    //这里注入的demoService是DemoServiceShanghai,还是DemoServiceBeijing?    @Resource    IDemoService demoService;      @Test    void testDemoService() {        demoService.doSomething();    }}

当咱们执行这个测试用例的时候肯定会报错,因为Spring发现了两个IDemoService的实现类。它不晓得去实例化哪一个实现类,来作为IDemoService的理论业务解决bean。当然咱们冀望的状态是:

  • 在北京部署零碎的时候,应用DemoServiceBeijing作为IDemoService的实现类实现依赖注入
  • 在上海部署零碎的时候,应用DemoServiceShanghai作为IDemoService的实现类实现依赖注入

二、绝对低级解决方案

面对下面的需要,先说几个绝对低级的解决方案,这几个计划尽管能够实现咱们冀望的状态,然而对运维不够敌对。

2.1. 计划一:应用@Primary注解

如果在北京部署零碎的时候,在DemoServiceBeijing的类下面加上@Primary,该注解的作用就是强制从多个实现类外面选一个实现类,如果Spring不晓得选哪一个,咱们通知它一个默认的。

@Primary@Componentpublic class DemoServiceBeijing implements IDemoService {

2.2. 计划二:应用@Resource注解

因为Resource注解默认应用名称进行依赖注入,所以变量名明确叫做demoServiceBeijing(首字母小写),应用的就是DemoServiceBeijing实现类。

@ResourceIDemoService demoServiceBeijing;  //这里的变量名称指定了bean名称//IDemoService demoService;  被替换掉

或者

@Resource(name = "demoServiceBeijing")  //应用resource注解明确指定名称IDemoService demoService;

2.3.计划三:应用@Qualifier注解

与上文同样的情理,应用@Qualifier注解,指定bean的名称进行依赖注入

@Qualifier("demoServiceBeijing")  //应用Qualifier注解明确指定名称@ResourceIDemoService demoService;

下面所提到的三个计划尽管都能够解决:在不同的部署环境下应用不同的接口实现类实现依赖注入的问题。然而这样不好,因为一旦咱们要把部署环境从beijing(北京)换成shanghai(上海),就须要把下面的注解的地位或者内容全都批改一遍(所有的实现类代码都要批改)。

三、绝对高级的解决方案

咱们提出进一步的冀望:就是只批改一个配置就能实现部署环境切换的操作。比方:

deploy:  province: beijing

当咱们冀望把部署环境从北京切换到上海的时候,只须要将上文配置中的beijing 改成 shanghai ,这该怎么实现呢?

  • 在北京的实现类下面加上ConditionalOnProperty注解,havingValue的值为beijing
@Component@ConditionalOnProperty(value="deploy.province",havingValue = "beijing")public class DemoServiceBeijing implements IDemoService {
  • 在上海的实现类下面加上ConditionalOnProperty注解,havingValue的值为shanghai
@Component@ConditionalOnProperty(value="deploy.province",havingValue = "shanghai")public class DemoServiceShanghai implements IDemoService {

ConditionalOnProperty注解在这里的作用就是:读取配置文件发现deploy.province,并将该配置的值与havingValue匹配,匹配上哪一个就实例化哪一个类作为该接口的实现类bean注入到Spring容器中(当然注入过程须要配合@Component注解实现)。

欢送关注我的布告号:字母哥杂谈,回复003赠送作者专栏《docker修炼之道》的PDF版本,30余篇精品docker文章。字母哥博客:zimug.com