一、问题的描述

在实际的系统应用开发中我经常会遇到这样的一类需求,相信大家在工作中也会经常遇到:

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

遇到这样的需求,我们通常会定义一个业务实现的接口,比如:

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

spring接口多实现类,该依赖注入哪一个?的更多相关文章

  1. 详解 Spring 3.0 基于 Annotation 的依赖注入实现(转)

    使用 @Repository.@Service.@Controller 和 @Component 将类标识为 Bean Spring 自 2.0 版本开始,陆续引入了一些注解用于简化 Spring 的 ...

  2. 轻松了解Spring中的控制反转和依赖注入(二)

    紧接上一篇文章<轻松了解Spring中的控制反转和依赖注入>讲解了SpringIOC和DI的基本概念,这篇文章我们模拟一下SpringIOC的工作机制,使我们更加深刻的理解其中的工作. 类 ...

  3. 详解 Spring 3.0 基于 Annotation 的依赖注入实现--转载

    使用 @Repository.@Service.@Controller 和 @Component 将类标识为 Bean Spring 自 2.0 版本开始,陆续引入了一些注解用于简化 Spring 的 ...

  4. 详解 Spring 3.0 基于 Annotation 的依赖注入实现

    Spring 的依赖配置方式与 Spring 框架的内核自身是松耦合设计的.然而,直到 Spring 3.0 以前,使用 XML 进行依赖配置几乎是唯一的选择.Spring 3.0 的出现改变了这一状 ...

  5. SSM框架之Spring(2)IOC及依赖注入

    Spring(2)IOC及依赖注入 基于xml配置文件的实现 1.IOC (控制反转-Inversion Of Control) 控制反转(Inversion of Control,缩写为IoC),是 ...

  6. Spring中的控制反转和依赖注入

    Spring中的控制反转和依赖注入 原文链接:https://www.cnblogs.com/xxzhuang/p/5948902.html 我们回顾一下计算机的发展史,从最初第一台计算机的占地面积达 ...

  7. Spring 04: IOC控制反转 + DI依赖注入

    Spring中的IOC 一种思想,两种实现方式 IOC (Inversion of Control):控制反转,是一种概念和思想,指由Spring容器完成对象创建和依赖注入 核心业务:(a)对象的创建 ...

  8. Spring 源码分析之 bean 依赖注入原理(注入属性)

         最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...

  9. SSM框架之Spring(3)IOC及依赖注入(基于注解的实现)

    Spring(3)IOC及依赖注入(基于注解的实现) 学习基于注解的 IoC 配置,大家脑海里首先得有一个认知,即注解配置和 xml 配置要实现的功能都是一样 的,都是要降低程序间的耦合.只是配置的形 ...

随机推荐

  1. 一个 curl 配置引发的惨案

    问题 这两天想装新版本的 node,发现 nvm 一直报下面这个错误.我反复 Google 了,但是并没有找到一条我能用的. 痛苦 我起初一直怀疑是我用的 zsh-nvm 抽疯,所以今天有空就把它还有 ...

  2. 高度灵活可定制的PC布局:头部按钮、左边栏、右边栏、状态栏

    什么是自适应布局 CabloyJS提供了一套布局管理器,实现自适应布局 关于自适应布局的概念,强烈建议先阅读以下两篇文章: 自适应布局:pc = mobile + pad 自适应布局:视图尺寸 什么是 ...

  3. 如何在 Mac 和虚拟机上安装 macOS Big Sur、Monterey 和 Ventura

    请访问原文链接:https://sysin.org/blog/how-to-install-macos/,查看最新版.原创作品,转载请保留出处. 作者主页:www.sysin.org 名词解释: 硬件 ...

  4. UiPath程序设计文档

    1. [RPA之家]添加数据列UiPath.Core.Activities.AddDataColumn 链接: https://pan.baidu.com/s/1RRMw4voqJru-fJSoC3W ...

  5. rhel挂载本地光盘为yum源

    挂载光盘 mount /dev/sr0 /mnt/cdrom mkdir /mnt/cdrom 临时挂载 mount /dev/sr0 /mnt/cdrom 永久挂载光盘 mount -a 执行挂载 ...

  6. ssh-配置及使用

    ssh配置文件 SSH的配置文件在/etc/ssh/目录下     openssh-client安装后,生成的配置文件为ssh_config,主要用于连接其他linux主机时,加载此文件     op ...

  7. java,捕获和抛出异常

    package Exrro; public class Test { //ctrl + alt + T快速生成异常捕捉 public static void main(String[] args) { ...

  8. 关于 Python 的 import

    好久以前就被 Python 的相对与绝对导入所困扰.去年粗浅探究后自以为完全理解,近来又因 sys.path[0] 和 os.getcwd() 的不一致而刷新了认知... Python 官方文档 5. ...

  9. 5-9 Leaf 分布式ID

    Leaf 什么Leaf leaf是叶子的意思 我们使用的Leaf是美团公司开源的一个分布式序列号(id)生成系统 我们可以在Github网站上下载项目直接使用 为什么需要Leaf 上面的图片中 是一个 ...

  10. Solution -「Hdu3037」Saving Beans

    Prob. 给定 \(m\) 个相同球,\(n\) 个不同的盒子. 求在这 \(n\) 个盒子中放不超过 \(m\) 个球的方案数,并对 \(p\) 取模. 其中 \(1 \leq n, m \leq ...