乐趣区

关于java:spring接口多实现类该依赖注入哪一个

一、问题的形容

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

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

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

public interface IDemoService {public void doSomething();
}

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

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

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

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

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

@SpringBootTest
class 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
@Component
public class DemoServiceBeijing implements IDemoService {

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

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

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

或者

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

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

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

@Qualifier("demoServiceBeijing")  // 应用 Qualifier 注解明确指定名称
@Resource
IDemoService 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

退出移动版