一、问题的描述

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

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

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

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. 蓝牙、WiFi、ZigBee三大无线通信技术协议模块哪一个是最好的?

    曾经,在2015年极客公园创新大会上,小米首次在非官方平台发布了新款产品小米智能家庭套装.自此,Zigbee便常出现在大众视野中. 如今,小米在IoT物联网应用开发者平台上明确说明,不再推广Zigbe ...

  2. 在sqlbolt上学习SQL

    在sqlbolt上学习SQL 该网站能够学习sql基础,并且能在网页中直接输入sql语句进行查询. 学习网站原网址https://sqlbolt.com/(!部分指令该网站不支持,且存在一些bug!) ...

  3. NCF 的Azure Cosmos DB 演示案例

    简介 NCF想必看过我之前发的NCF的文章的同学们都已经很熟悉了 今天我们要来聊一聊的是NCF遇到Azure Cosmos DB后会碰撞出什么样的火花,让我们一起往下看 我们先来说说什么是Azure ...

  4. pyenv安装及使用教程

    pyenv安装及使用教程 pyenv 安装 git clone https://github.com/pyenv/pyenv.git ~/.pyenv # 编辑 bashrc vim ~/.bashr ...

  5. kali 无线网络渗透测试

    一.无线网络渗透嗅探工具Kismet 如果要进行无线网络渗透测试,则必须先扫描所有有效的无线接入点.在Kali linux中,提供了一款嗅探无线网络工具Kismet.使用该工具可以测量周围的无线信号, ...

  6. django生成迁移文件和执行迁移的命令

    生成迁移文件: python manage.py makemigrations    #创建数据库迁移文件 执行迁移: python manage.py migrate    # 根据数据库迁移文件生 ...

  7. Unsupported major.minor version 52.0 (unable to load class org.apache.kafka.clients.producer.Produce异常解决方法

    在控制台输入java -version,查看自己的版本是多少,我的查出来是1.8的.随后将服务器上的改为1.8的就可以了.

  8. JavaWEB-01-MySQL基础

    JavaWeb内容 数据库 – 数据存储 MySQL JDBC Maven - 项目管理工具 Mybatis 前端 - 为了前端哥们沟通 HTML+CSS JavaScript Ajax + Vue ...

  9. Eclipse Ctrl+鼠标左键不能查看源代码

    查询当前项目的使用的java包版本. 找到java包相应版本的安装路径. 在 "Source Attachment"对话框下,选择"External location&q ...

  10. 从零开始完整开发基于websocket的在线对弈游戏【五子棋】,只用几十行代码完成全部逻辑。

    五子棋是规则简单明了的策略型游戏,先形成五子连线者获胜.本课程习作采用两人在线对弈的方式进行比赛,拿着手机在上下班路上玩特别合适. 整个过程在众触低代码应用平台进行,使用表达式描述游戏逻辑(高度简化版 ...