当前位置: 首页 > 后端技术 > Java

spring接口的实现类有多个,应该注入哪个?

时间:2023-04-01 13:16:08 Java

1。问题描述在实际的系统应用开发中,经常会遇到这样的需求。相信大家在工作中会经常遇到:同一个系统部署在多个省份。北京某服务是根据北京用户的需求而采取的一种实施方式。同样的业务,在上海用另一种方式实现,与北京的方式类似。为了满足这样的需求,我们通常会定义一个业务实现的接口,比如:北京环境下的publicinterfaceIDemoService{publicvoiddoSomething();}这样实现,比如:@ComponentpublicclassDemoServiceBeijingimplementsIDemoService{@OverridepublicvoiddoSomething(){System.out.println("北京业务实现");}}在上海环境实现,例如:@ComponentpublicclassDemoServiceShanghaiimplementsIDemoService{@OverridepublicvoiddoSomething(){System.out.println("上海的业务实现");}}然后我们写一个模拟业务测试用例@SpringBootTestclassDemoApplicationTests{//这里注入的demoService是DemoServiceShanghai还是DemoServiceBeijing?@ResourceIDemoService演示服务;@TestvoidtestDemoService(){demoService.doSomething();}}当我们执行这个测试用例的时候,会报错,因为Spring找到了两个IDemoService的实现类。它不知道将哪个实现类实例化为IDemoService的实际业务处理bean。当然,我们期望的状态是:在北京部署系统时,使用DemoServiceBeijing作为IDemoService的实现类,完成依赖注入。在上海部署系统时,使用DemoServiceShanghai作为IDemoService的实现类,完成依赖注入。2.相对底层的解决方案面对上面首先说几个相对底层的解决方案。这些方案虽然可以达到我们想要的状态,但是对运维不够友好。2.1.解决方案1:使用@Primary注释。如果你在北京部署系统的时候给DemoServiceBeijing类加上@Primary,这个注解的作用就是强制你从多个实现类中选择一个实现类。如果Spring不知道选择哪个One,我们告诉它一个默认值。@Primary@ComponentpublicclassDemoServiceBeijing实现IDemoService{2.2.方案二:使用@Resource注解,因为Resource注解默认使用一个名字进行依赖注入,所以变量名明确叫demoServiceBeijing(首字母小写),使用的是DemoServiceBeijing实现类。@ResourceIDemoServicedemoServiceBeijing;//这里的变量名指定bean名//IDemoServicedemoService;replacedor@Resource(name="demoServiceBeijing")//使用资源注解明确指定名称IDemoServicedemoService;2.3.方案三:使用@Qualifier注解同上,使用@Qualifier注解指定依赖注入的bean的名字@Qualifier("demoServiceBeijing")//使用Qualifier注解指定名字@ResourceIDemoServicedemoService;虽然上面提到的三种方案都可以解决在不同的部署环境下使用不同的接口实现类来完成依赖注入的问题。但这并不好,因为一旦我们要将部署环境从beijing(北京)更改为shanghai(上海),就需要修改以上注解的位置或内容(所有实现代码都要修改)。3、对于比较高级的方案,我们提出了更进一步的期望:即只修改一个配置就可以完成切换部署环境的操作。例如:deploy:province:beijing当我们要将部署环境从北京切换到上海时,只需要将上面配置中的beijing改为shanghai即可。如何实现?在北京的实现类中添加ConditionalOnProperty注解,havingValue值为beijing@Component@ConditionalOnProperty(value="deploy.province",havingValue="beijing")publicclassDemoServiceBeijingimplementsIDemoService{在实现类中添加ConditionalOnPropertyShanghai注解,havingValue的值为shanghai@Component@ConditionalOnProperty(value="deploy.province",havingValue="shanghai")publicclassDemoServiceShanghaiimplementsIDemoService{这里ConditionalOnProperty注解的作用是:读取配置文件找到deploy.province,并将配置的值与havingValue进行匹配,匹配到哪个就会实例化哪个类作为该接口的实现类bean注入到Spring容器中(当然注入过程需要用@Component注解)。欢迎关注我的公告号:字母哥杂谈,回复003送作者专栏《docker修炼之道》30多篇优质docker文章PDF版。Antetokounmpo博客:zimug.com