一、問題的描述
在實際的系統應用開發中我經常會遇到這樣的一類需求,相信大家在作業中也會經常遇到:
- 同一個系統在多個省份部署,
- 一個業務在北京是一種實作方式,是基于北京用戶的需求,
- 同樣的業務在上海是另外一種實作方式,與北京的實作方式大同小異
遇到這樣的需求,我們通常會定義一個業務實作的介面,比如:
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="https://www.cnblogs.com/zimug/p/deploy.province",havingValue = "https://www.cnblogs.com/zimug/p/beijing")
public class DemoServiceBeijing implements IDemoService {
- 在上海的實作類上面加上ConditionalOnProperty注解,havingValue的值為shanghai
@Component
@ConditionalOnProperty(value="https://www.cnblogs.com/zimug/p/deploy.province",havingValue = "https://www.cnblogs.com/zimug/p/shanghai")
public class DemoServiceShanghai implements IDemoService {
ConditionalOnProperty注解在這里的作用就是:讀取組態檔發現deploy.province,并將該配置的值與havingValue匹配,匹配上哪一個就實體化哪一個類作為該介面的實作類bean注入到Spring容器中(當然注入程序需要配合@Component注解實作),
歡迎關注我的公告號:字母哥雜談,回復003贈送作者專欄《docker修煉之道》的PDF版本,30余篇精品docker文章,字母哥博客:zimug.com
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/502541.html
標籤:Java
上一篇:面試手撕并發演算法題
下一篇:CS、BS架構和網路通信協議
