使用SpringBoot根據(jù)配置注入接口的不同實(shí)現(xiàn)類(lèi)(代碼演示)
一.引言
我們?cè)谑褂胹pringboot進(jìn)行開(kāi)發(fā)的時(shí)候經(jīng)常用到@Autowired和@Resource進(jìn)行依賴(lài)注入,但是當(dāng)我們一個(gè)接口對(duì)應(yīng)多個(gè)不同的實(shí)現(xiàn)類(lèi)的時(shí)候如果不進(jìn)行一下配置項(xiàng)目啟動(dòng)時(shí)就會(huì)報(bào)錯(cuò),那么怎么根據(jù)不同的需求注入不同的類(lèi)型就是一個(gè)值得考慮的問(wèn)題,雖然@Autowired和@Resource就可以實(shí)現(xiàn),但是我們也可以選擇更加靈活的@ConditionalOnProperty注解來(lái)實(shí)現(xiàn)
二.代碼演示
1.問(wè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 {
//注入需要的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實(shí)現(xiàn)類(lèi)一 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實(shí)現(xiàn)類(lèi)二 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");
}
}這時(shí)我們的程序啟動(dòng)會(huì)報(bào)錯(cuò),大概意思就是找到了兩個(gè)實(shí)現(xiàn)類(lèi)
***************************
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的時(shí)候?qū)⒔涌谧兞棵臑閷?shí)現(xiàn)類(lèi)的限定名
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 {
//修改變量名為實(shí)現(xiàn)類(lèi)的限定名
@Autowired
TestService testServiceImplOne;
@RequestMapping("test")
public void test(){
testServiceImplOne.sayHello();
}
}我們可以將接口的命名改為對(duì)應(yīng)實(shí)現(xiàn)類(lèi)的限定名,默認(rèn)為類(lèi)名且首字母小寫(xiě),當(dāng)然我們也可以自己給接口的實(shí)現(xiàn)類(lèi)配置限定名,例如@Service("serviceOne") 之后在引用時(shí)使用我們配置的限定名,這樣程序都可以自動(dòng)找到實(shí)現(xiàn)類(lèi),測(cè)試結(jié)果如下:

2.2 使用@Autowired配合@Qualifier指定限定名注入實(shí)現(xiàn)類(lèi)
其實(shí)這個(gè)方法的原理和上面的很相似,@Autowired會(huì)默認(rèn)根據(jù)type進(jìn)行注入,如果type相同會(huì)根據(jù)id進(jìn)行注入,也就是我們說(shuō)的限定名,我們只需要讓它找到對(duì)應(yīng)限定名的類(lèi)即可,上面我們通過(guò)修改接口變量名的方式來(lái)實(shí)現(xiàn),同時(shí)我們還可以配合@Qualifier注解來(lái)實(shí)現(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)然,和上一種方法相同,我們注解中填的值是實(shí)現(xiàn)類(lèi)的限定名,可以使用默認(rèn),也可以和上面一樣在使用@Service時(shí)進(jìn)行配置,測(cè)試結(jié)果如下:

2.3@ConditionalOnProperty
以上兩種方法都是硬編碼方式,在我們需要進(jìn)行用戶(hù)配置時(shí)很不方便,所以我們可以使用@ConditionalOnProperty注解來(lái)實(shí)現(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");
}
}在配置文件中配置我們使用的類(lèi)

測(cè)試結(jié)果如下

三.總結(jié)
前兩種方法都是去尋找接口的限定名,第三種方法中@ConditionalOnProperty(name = "serviceControl",havingValue = "serviceOne")注解的name屬性對(duì)應(yīng)配置文件中的key值,而havingValue屬性對(duì)應(yīng)的是配置文件中我們上面定義的name屬性對(duì)應(yīng)的value值
到此這篇關(guān)于SpringBoot根據(jù)配置注入接口的不同實(shí)現(xiàn)類(lèi)的文章就介紹到這了,更多相關(guān)SpringBoot注入接口實(shí)現(xiàn)類(lèi)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot頂層接口實(shí)現(xiàn)類(lèi)注入項(xiàng)目的方法示例
- SpringBoot通過(guò)Filter實(shí)現(xiàn)整個(gè)項(xiàng)目接口的SQL注入攔截詳解
- Springboot根據(jù)配置文件動(dòng)態(tài)注入接口實(shí)現(xiàn)類(lèi)詳解
- springboot接口多實(shí)現(xiàn)類(lèi)選擇性注入解決方案
- SpringBoot使用@Autowired為多實(shí)現(xiàn)的接口注入依賴(lài)
- 使用Springboot根據(jù)配置文件動(dòng)態(tài)注入接口實(shí)現(xiàn)類(lèi)
- SpringBoot中多個(gè)實(shí)現(xiàn)的接口正確注入的六種方式
相關(guān)文章
Java 詳細(xì)講解線程安全與同步附實(shí)例與注釋
線程安全是多線程編程時(shí)的計(jì)算機(jī)程序代碼中的一個(gè)概念。在擁有共享數(shù)據(jù)的多條線程并行執(zhí)行的程序中,線程安全的代碼會(huì)通過(guò)同步機(jī)制保證各個(gè)線程都可以正常且正確的執(zhí)行,不會(huì)出現(xiàn)數(shù)據(jù)污染等意外情況2022-04-04
解決DataInputStream?read不等于-1,socket文件傳輸只能傳輸一個(gè)文件無(wú)法傳輸多個(gè)問(wèn)題
這篇文章主要介紹了解決DataInputStream?read不等于-1,socket文件傳輸只能傳輸一個(gè)文件無(wú)法傳輸多個(gè)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
Java動(dòng)態(tài)規(guī)劃之丑數(shù)問(wèn)題實(shí)例講解
這篇文章主要介紹了Java動(dòng)態(tài)規(guī)劃之丑數(shù)問(wèn)題實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-09-09
java 動(dòng)態(tài)加載的實(shí)現(xiàn)代碼
這篇文章主要介紹了java 動(dòng)態(tài)加載的實(shí)現(xiàn)代碼的相關(guān)資料,Java動(dòng)態(tài)加載類(lèi)主要是為了不改變主程序代碼,通過(guò)修改配置文件就可以操作不同的對(duì)象執(zhí)行不同的功能,需要的朋友可以參考下2017-07-07
詳解Java ES多節(jié)點(diǎn)任務(wù)的高效分發(fā)與收集實(shí)現(xiàn)
ElasticSearch 是一個(gè)高可用開(kāi)源全文檢索和分析組件。提供存儲(chǔ)服務(wù),搜索服務(wù),大數(shù)據(jù)準(zhǔn)實(shí)時(shí)分析等。一般用于提供一些提供復(fù)雜搜索的應(yīng)用2021-06-06
IDEA導(dǎo)入外部項(xiàng)目報(bào)Error:java: 無(wú)效的目標(biāo)發(fā)行版: 11的解決方法
這篇文章主要介紹了IDEA導(dǎo)入外部項(xiàng)目報(bào)Error:java: 無(wú)效的目標(biāo)發(fā)行版: 11,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
詳解mybatis多對(duì)一關(guān)聯(lián)查詢(xún)的方式
這篇文章主要給大家介紹了關(guān)于mybatis多對(duì)一關(guān)聯(lián)查詢(xún)的相關(guān)資料,文中將關(guān)聯(lián)方式以及配置方式介紹的很詳細(xì),需要的朋友可以參考下2021-06-06
SpringBoot自定義bean綁定實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot自定義bean綁定,最常見(jiàn)的配置綁定的場(chǎng)景,是在自定義的bean中通過(guò)@Value注解將某個(gè)屬性和對(duì)應(yīng)的配置綁定2022-10-10

