一、问题的描述

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

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

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

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. django框架4

    内容概要 编辑删除功能编写 虚拟环境 django路由层版本区别 视图函数的返回值 JsonResponse对象 form表单上传文件 request其他方法 FBV与CBV(基于函数的视图.基于类的 ...

  2. VSCode 安装以及初步使用教程

    老样子先介绍一下VSCode(是什么?干什么?有什么用?好处是什么?等) VisualStudioCode(简称VSCode)是Microsoft开发的代码编辑器,它支持Windows,Linux和m ...

  3. 【Pr】基础流程

    新建工程 1.打开Pr 2.点击"新建""项目" 3.在电脑磁盘上新建好项目想要存放的位置,比如Demo1,为了便于管理,我先新建了一个Demo文件夹,再在里边 ...

  4. 我熬夜开发了一款简约实用、支持多平台的Markdown在线编辑器(开源)

    前言 之前,一直想开发一款属于自己的Markdown编辑器,主要是自己平常写文章可以更加灵活操作,另外扩宽自己的视野也是非常不错的选择啊!所以在周末就决定玩耍一番.首先我调研了很多线上热门的md编辑器 ...

  5. UiPath文本操作Set Text的介绍和使用

    一.Set Text的介绍 向输入框/文本框写入文本的一种操作 二.Set Text在UiPath中的使用 1.打开设计器,在设计库中新建一个Sequence,为序列命名及设置Sequence存放的路 ...

  6. 如何参与开源项目 - 细说 GitHub 上的 PR 全过程

    目录 一.概述 二.为什么要参与开源项目 三.为什么我想介绍如何 PR 四.我想参与开源项目,怎么开始? 4.1.寻找一个合适的开源项目 4.2.寻找贡献点 五.我要提交 PR,怎么上手? 5.1.第 ...

  7. WannaRen来袭:螣龙安科带你盘点那些年的勒索病毒

    2020年4月7日,360CERT监测发现网络上出现一款新型勒索病毒wannaRen,该勒索病毒会加密windows系统中几乎所有的文件,并且以.WannaRen作为后缀.360CERT该事件评定:危 ...

  8. java getway springcloud 记录请求数据

    java getway springcloud 记录请求数据,兼容post请求无参数和response返回无参数 方式1 import com.icar.web.icarutils.util.Clie ...

  9. CF1703A YES or YES? 题解

    题意:输入一个长度为 \(3\) 的字符串,判断其是否为 \(YES\),忽略大小写. 做法:输入字符串,直接判断. #include<cstdio> #include<iostre ...

  10. 2022-7-12 第五组 pan小堂 js

    JavaScript Switch 语句 (熟悉掌握) 请使用 switch 语句来选择多个需被执行的代码块之一. 语法: switch(表达式){ case n: 代码块 break; case n ...