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
spring接口多实现类,该依赖注入哪一个?的更多相关文章
- 详解 Spring 3.0 基于 Annotation 的依赖注入实现(转)
使用 @Repository.@Service.@Controller 和 @Component 将类标识为 Bean Spring 自 2.0 版本开始,陆续引入了一些注解用于简化 Spring 的 ...
- 轻松了解Spring中的控制反转和依赖注入(二)
紧接上一篇文章<轻松了解Spring中的控制反转和依赖注入>讲解了SpringIOC和DI的基本概念,这篇文章我们模拟一下SpringIOC的工作机制,使我们更加深刻的理解其中的工作. 类 ...
- 详解 Spring 3.0 基于 Annotation 的依赖注入实现--转载
使用 @Repository.@Service.@Controller 和 @Component 将类标识为 Bean Spring 自 2.0 版本开始,陆续引入了一些注解用于简化 Spring 的 ...
- 详解 Spring 3.0 基于 Annotation 的依赖注入实现
Spring 的依赖配置方式与 Spring 框架的内核自身是松耦合设计的.然而,直到 Spring 3.0 以前,使用 XML 进行依赖配置几乎是唯一的选择.Spring 3.0 的出现改变了这一状 ...
- SSM框架之Spring(2)IOC及依赖注入
Spring(2)IOC及依赖注入 基于xml配置文件的实现 1.IOC (控制反转-Inversion Of Control) 控制反转(Inversion of Control,缩写为IoC),是 ...
- Spring中的控制反转和依赖注入
Spring中的控制反转和依赖注入 原文链接:https://www.cnblogs.com/xxzhuang/p/5948902.html 我们回顾一下计算机的发展史,从最初第一台计算机的占地面积达 ...
- Spring 04: IOC控制反转 + DI依赖注入
Spring中的IOC 一种思想,两种实现方式 IOC (Inversion of Control):控制反转,是一种概念和思想,指由Spring容器完成对象创建和依赖注入 核心业务:(a)对象的创建 ...
- Spring 源码分析之 bean 依赖注入原理(注入属性)
最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...
- SSM框架之Spring(3)IOC及依赖注入(基于注解的实现)
Spring(3)IOC及依赖注入(基于注解的实现) 学习基于注解的 IoC 配置,大家脑海里首先得有一个认知,即注解配置和 xml 配置要实现的功能都是一样 的,都是要降低程序间的耦合.只是配置的形 ...
随机推荐
- 2020.09.12【NOIP提高组&普及组】模拟赛C组 总结
总结:这次比赛成绩并不理想,虽然策略得当 \(P.S.\):太多题有多组数据,但是样例只有一个数据 各题题解和改题情况 T1 匹配 题面 描述 给你一个由{a,b-z,A,B-.Z}组成的字符串,我们 ...
- php7.1 安装amqp扩展
在php开发中使用rabbitmq消息队列时,需要安装PHP扩展amqp,安装步骤如下: 直接使用pecl进行amqp扩展的安装, /usr/local/php/bin/pecl install am ...
- BI与SaaS碰撞,让数据处理更加轻松(下)
背景 在上篇内容中,我们从SaaS各种功能的角度为大家介绍了在数据处理中SaaS的巨大价值,而本次我们将用实例将为大家展示SaaS与BI间的碰撞又会产生怎样的火花. BI与SaaS集成示例 通常BI分 ...
- redis持久化之RDB (七)
一:什么是redis的持久化 Redis 持久化 Redis 提供了不同级别的持久化方式: RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储. AOF持久化方式记录每次对服务器写的操作,当 ...
- 1.为什么要从古典概率入门概率学《zobol的考研概率论教程》
在入门概率论与数理统计这门课中,刚开始我们都会从古典概率开始学习,为什么要选择它呢?这是因为古典概率作为一种将生活中的事情简化为有限种情况,并假设它们的发生可能差不多的手段,十分的好用且简洁. 这里我 ...
- BUUCTF-[BJDCTF2020]藏藏藏
[BJDCTF2020]藏藏藏 打开图片发现存在压缩包,使用foremost分离一下. 得到压缩包,直接可以解压. 解码一下就可以得到flag
- Vue回炉重造之三次封装axios
源码目录 在src目录下建立一个request文件夹.里面建立两个文件: http.js api.js 源码内容 http.js import axios from 'axios' // 引入axio ...
- 使用 Abp.Zero 搭建第三方登录模块(一):原理篇
第三方登录是基于用户在第三方平台上(如微信,QQ, 百度)已有的账号来快速完成系统的登录.注册-登录等功能. 微信的鉴权 以微信的鉴权为例: 假如你的网站有一个扫码登录的功能,会弹出一个由微信提供的 ...
- Linux命令格式、终端类型和获取帮助的方法
Linux用户类型 Root用户:超级管理员,权限很大 普通用户:权限有限 终端 terminal 终端类型 物理终端:鼠标.键盘.显示器 虚拟终端:软件模拟出来的终端 控制台终端: /dev/con ...
- bat-进程与服务
进程 tasklist 查看进程表 关闭进程 taskkill /PID xxx taskkill -f -im unm* taskkill -f -im ice* 服务 **net** net命令不 ...