使用SpringBoot根據(jù)配置注入接口的不同實現(xiàn)類(代碼演示)
一.引言
我們在使用springboot進行開發(fā)的時候經(jīng)常用到@Autowired和@Resource進行依賴注入,但是當(dāng)我們一個接口對應(yīng)多個不同的實現(xiàn)類的時候如果不進行一下配置項目啟動時就會報錯,那么怎么根據(jù)不同的需求注入不同的類型就是一個值得考慮的問題,雖然@Autowired和@Resource就可以實現(xiàn),但是我們也可以選擇更加靈活的@ConditionalOnProperty注解來實現(xiàn)
二.代碼演示
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實現(xiàn)類一 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實現(xiàn)類二 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"); } }
這時我們的程序啟動會報錯,大概意思就是找到了兩個實現(xiàn)類
***************************
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的時候?qū)⒔涌谧兞棵臑閷崿F(xiàn)類的限定名
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 { //修改變量名為實現(xiàn)類的限定名 @Autowired TestService testServiceImplOne; @RequestMapping("test") public void test(){ testServiceImplOne.sayHello(); } }
我們可以將接口的命名改為對應(yīng)實現(xiàn)類的限定名,默認為類名且首字母小寫,當(dāng)然我們也可以自己給接口的實現(xiàn)類配置限定名,例如@Service("serviceOne") 之后在引用時使用我們配置的限定名,這樣程序都可以自動找到實現(xiàn)類,測試結(jié)果如下:
2.2 使用@Autowired配合@Qualifier指定限定名注入實現(xiàn)類
其實這個方法的原理和上面的很相似,@Autowired會默認根據(jù)type進行注入,如果type相同會根據(jù)id進行注入,也就是我們說的限定名,我們只需要讓它找到對應(yīng)限定名的類即可,上面我們通過修改接口變量名的方式來實現(xiàn),同時我們還可以配合@Qualifier注解來實現(xiàn)相同的目的
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(); } }
當(dāng)然,和上一種方法相同,我們注解中填的值是實現(xiàn)類的限定名,可以使用默認,也可以和上面一樣在使用@Service時進行配置,測試結(jié)果如下:
2.3@ConditionalOnProperty
以上兩種方法都是硬編碼方式,在我們需要進行用戶配置時很不方便,所以我們可以使用@ConditionalOnProperty注解來實現(xiàn)配置文件控制的功能
在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"); } }
在配置文件中配置我們使用的類
測試結(jié)果如下
三.總結(jié)
前兩種方法都是去尋找接口的限定名,第三種方法中@ConditionalOnProperty(name = "serviceControl",havingValue = "serviceOne")注解的name屬性對應(yīng)配置文件中的key值,而havingValue屬性對應(yīng)的是配置文件中我們上面定義的name屬性對應(yīng)的value值
到此這篇關(guān)于SpringBoot根據(jù)配置注入接口的不同實現(xiàn)類的文章就介紹到這了,更多相關(guān)SpringBoot注入接口實現(xiàn)類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SSh結(jié)合Easyui實現(xiàn)Datagrid的分頁顯示
這篇文章主要為大家詳細介紹了SSh結(jié)合Easyui實現(xiàn)Datagrid的分頁顯示的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-06-06java中實現(xiàn)map與對象相互轉(zhuǎn)換的幾種實現(xiàn)
這篇文章主要介紹了java中實現(xiàn)map與對象相互轉(zhuǎn)換的幾種實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07Springboot實現(xiàn)Java阿里短信發(fā)送代碼實例
這篇文章主要介紹了springboot實現(xiàn)Java阿里短信發(fā)送代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-02-02加速spring/springboot應(yīng)用啟動速度詳解
這篇文章主要介紹了加速spring/springboot應(yīng)用啟動速度詳解,本文通過實例代碼給大家介紹的非常詳細對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07Java設(shè)計模式之抽象工廠模式AbstractFactoryPattern詳解
這篇文章主要介紹了Java設(shè)計模式之抽象工廠模式AbstractFactoryPattern詳解,抽象工廠模式是一種軟件開發(fā)設(shè)計模式,抽象工廠模式提供了一種方式,可以將一組具有同一主題的單獨的工廠封裝起來,需要的朋友可以參考下2023-10-10Java使用正則表達式檢索、替換String中特定字符和正則表達式的一切
這篇文章主要給大家介紹了關(guān)于Java使用正則表達式檢索、替換String中特定字符和正則表達式的一切,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09