使用SpringBoot根据配置注入接口的不同实现类(代码演示)

目录

一.引言

二.代码演示

1.问题描述

2.解决方案

2.1使用@Autowired的时候将接口变量名改为实现类的限定名

2.2 使用@Autowired配合@Qualifier指定限定名注入实现类

2.3@ConditionalOnProperty

 三.总结

一.引言

我们在使用springboot进行开发的时候经常用到@Autowired@Resource进行依赖注入,但是当我们一个接口对应多个不同的实现类的时候如果不进行一下配置项目启动时就会报错,那么怎么根据不同的需求注入不同的类型就是一个值得考虑的问题,虽然@Autowired@Resource就可以实现,但是我们也可以选择更加灵活的@ConditionalOnProperty注解来实现

二.代码演示 1.问题描述

TestController.java

package com.example.demo.controller; import com.example.demo.service.TestService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @ClassName TestController * @Author xuwei * @DATE 2022/6/28 */ @RestController @RequestMapping("test") public class TestController { //注入需要的service @Autowired TestService testService; @RequestMapping("test") public void test(){ testService.sayHello(); } }

 TestService.java

package com.example.demo.service; /** * @InterfaceName TestService * @Author xuwei * @DATE 2022/6/28 */ public interface TestService { /** * sayHello方法 */ void sayHello(); }

TestService实现类一  TestServiceImplOne.java

package com.example.demo.service.impl; import com.example.demo.service.TestService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @ClassName TestServiceImplOne * @Author xuwei * @DATE 2022/6/28 */ @Service public class TestServiceImplOne implements TestService { private static final Logger LOGGER = LoggerFactory.getLogger(TestServiceImplOne.class); /** * sayHello方法 */ @Override public void sayHello() { LOGGER.info("I am TestServiceImplOne"); } }

TestService实现类二 TestServiceImplTwo.java

package com.example.demo.service.impl; import com.example.demo.service.TestService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @ClassName TestServiceImplTwo * @Author xuwei * @DATE 2022/6/28 */ @Service public class TestServiceImplTwo implements TestService { private static final Logger LOGGER = LoggerFactory.getLogger(TestServiceImplTwo.class); /** * sayHello方法 */ @Override public void sayHello() { LOGGER.info("I am TestServiceImplTwo"); } }

这时我们的程序启动会报错,大概意思就是找到了两个实现类

***************************
APPLICATION FAILED TO START
***************************
Description:
Field testService in com.example.demo.controller.TestController required a single bean, but 2 were found:
    - testServiceImplOne: defined in file [/Users/xuwei/Desktop/Projects/IdeaProjects/demo/target/classes/com/example/demo/service/impl/TestServiceImplOne.class]
    - testServiceImplTwo: defined in file [/Users/xuwei/Desktop/Projects/IdeaProjects/demo/target/classes/com/example/demo/service/impl/TestServiceImplTwo.class]
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

2.解决方案 2.1使用@Autowired的时候将接口变量名改为实现类的限定名

TestController.java修改为如下

package com.example.demo.controller; import com.example.demo.service.TestService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @ClassName TestController * @Author xuwei * @DATE 2022/6/28 */ @RestController @RequestMapping("test") public class TestController { //修改变量名为实现类的限定名 @Autowired TestService testServiceImplOne; @RequestMapping("test") public void test(){ testServiceImplOne.sayHello(); } }

我们可以将接口的命名改为对应实现类的限定名,默认为类名且首字母小写,当然我们也可以自己给接口的实现类配置限定名,例如@Service("serviceOne") 之后在引用时使用我们配置的限定名,这样程序都可以自动找到实现类,测试结果如下:

2.2 使用@Autowired配合@Qualifier指定限定名注入实现类

其实这个方法的原理和上面的很相似,@Autowired会默认根据type进行注入,如果type相同会根据id进行注入,也就是我们说的限定名,我们只需要让它找到对应限定名的类即可,上面我们通过修改接口变量名的方式来实现,同时我们还可以配合@Qualifier注解来实现相同的目的

TestController.java修改为如下

package com.example.demo.controller; import com.example.demo.service.TestService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @ClassName TestController * @Author xuwei * @DATE 2022/6/28 */ @RestController @RequestMapping("test") public class TestController { //配合注解指定限定名 @Qualifier("testServiceImplTwo") @Autowired TestService testService; @RequestMapping("test") public void test(){ testService.sayHello(); } }

当然,和上一种方法相同,我们注解中填的值是实现类的限定名,可以使用默认,也可以和上面一样在使用@Service时进行配置,测试结果如下:

2.3@ConditionalOnProperty

以上两种方法都是硬编码方式,在我们需要进行用户配置时很不方便,所以我们可以使用@ConditionalOnProperty注解来实现配置文件控制的功能

在TestController中使用@Resource注入

package com.example.demo.controller; import com.example.demo.service.TestService; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @ClassName TestController * @Author xuwei * @DATE 2022/6/28 */ @RestController @RequestMapping("test") public class TestController { //使用@Resource注入 @Resource TestService testService; @RequestMapping("test") public void test(){ testService.sayHello(); } }

TestServiceImplOne.java

package com.example.demo.service.impl; import com.example.demo.service.TestService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; /** * @ClassName TestServiceImplOne * @Author xuwei * @DATE 2022/6/28 */ @Component @ConditionalOnProperty(name = "serviceControl",havingValue = "serviceOne") public class TestServiceImplOne implements TestService { private static final Logger LOGGER = LoggerFactory.getLogger(TestServiceImplOne.class); /** * sayHello方法 */ @Override public void sayHello() { LOGGER.info("I am TestServiceImplOne"); } }

TestServiceImplTwo.java

package com.example.demo.service.impl; import com.example.demo.service.TestService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; /** * @ClassName TestServiceImplTwo * @Author xuwei * @DATE 2022/6/28 */ @Component @ConditionalOnProperty(name = "serviceControl",havingValue = "serviceTwo") public class TestServiceImplTwo implements TestService { private static final Logger LOGGER = LoggerFactory.getLogger(TestServiceImplTwo.class); /** * sayHello方法 */ @Override public void sayHello() { LOGGER.info("I am TestServiceImplTwo"); } }

在配置文件中配置我们使用的类

测试结果如下

 三.总结

前两种方法都是去寻找接口的限定名,第三种方法中@ConditionalOnProperty(name = "serviceControl",havingValue = "serviceOne")注解的name属性对应配置文件中的key值,而havingValue属性对应的是配置文件中我们上面定义的name属性对应的value值

到此这篇关于SpringBoot根据配置注入接口的不同实现类的文章就介绍到这了,更多相关SpringBoot注入接口实现类内容请搜索易知道(ezd.cc)以前的文章或继续浏览下面的相关文章希望大家以后多多支持易知道(ezd.cc)!

推荐阅读

    学习写字楼新选择6000元主流配置

    学习写字楼新选择6000元主流配置,,这种配置需要考虑双核心的办公和娱乐平台,充分考虑办公室的办公需求和娱乐需求,以约6000元的预算和cost-e

    酷睿I7 配置

    酷睿I7 配置,配置,玩家国度啦华硕 Rampage II Extreme(3800元)如果米不够,也可以把Extreme改为Gene,不过是小板内存推荐金士顿6G DDR3 2000骇

    提高3A四核羿龙II游戏配置的性能

    提高3A四核羿龙II游戏配置的性能,,以节能环保为主题的IT产业,目前3A低端平台处理器、主板芯片组、独立开发卡性能突出,特别是在与AMD的处理

    opporeno8参数配置及价格

    opporeno8参数配置及价格,面部,亿元,Oppo的荣誉2020年1月4日,接近屏幕关闭传感器是否支持双卡:支持oppor11splus什么时候上市的Oppo R11S P

    查看配置:酷睿i3530集展示办公平台

    查看配置:酷睿i3530集展示办公平台,,由于时间和精力的关系,我们不可能对所有的配置进行评论,希望我们能理解,我希望我们的评论能在那些需要帮

    3500元超额值学生娱乐结构的优化配置

    3500元超额值学生娱乐结构的优化配置,,作为一个DIY的主流用户领域的学生,每个用户51学生攒机的高峰。因为学生用户没有稳定的收入来源,攒机

    计算机蓝屏故障的计算机蓝屏解决方案

    计算机蓝屏故障的计算机蓝屏解决方案,,电脑蓝屏电脑故障经常使用电脑的朋友经常遇到,因为电脑蓝屏是一个非常普遍的现象,所以很难预测,什么时

    公共CPU接口类型的详细描述

    公共CPU接口类型的详细描述,,我们知道CPU是电脑的大脑, CPU的处理速度直接决定电脑的性能, 那你知道CPU发展到现在, 都那些CPU接口类型吗.