前言
前幾天一個工程中,需要實現這樣一個場景:根據前端發送過來的請求參數的不同,走不同的 service(可同事走多個),最初我的思路是嘗試實現在 spring 中實現動態的依賴注入,也就是根據請求參數,動態的在 controller 中注入某個 service 接口的特定實現(接口有多個實現),但是發現這個實現不了,然后想了想,換了個思路,重新設計了一下,實現了需求中的場景。
附controller的分類:
正文
我的解決辦法是,使用“生產線工人工作能力自己掂量機制”來解決,這名字我自己起的,實際上就是想要實現按參數選擇走哪個 service 實現,可以一次性把所有 service 實現全都注入進來,然后依次請求,同時在每個 service 實現中寫一套規則判別方法,判斷當前請求自己是不是能夠處理,如果能夠處理,則進入處理方法,若自己沒有處理能力,則退出,讓請求走到其他 service 做同樣的判斷。形象點,可以想象一下,在一條生產線的傳送帶上傳送著不同品類的待加工的元部件,有若干工人排列在傳送帶旁邊,每個工人只會加工某一種元件,那么,當傳送帶上的元件傳送到自己面前時,需要判斷一下,自己有沒有處理這個元件的能力(掂量一下自己的能力),若有,取過來處理,若沒有,放過去讓別人走流程。
理解了其中邏輯,我們就來看代碼吧(片段):
1
2
3
4
5
6
7
8
|
public interface serviceprovider { // 掂量一下自己有沒有能力加工當前的元件(也就是request),能就返回 true 不能返回 false boolean support(request request); // 具體加工元件的邏輯 response execute(request request); } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@service public class serviceimpl implements service { // 注入一系列 service 數量不定 https://stackoverflow.com/questions/2153298/how-to-autowire-factorybean @resource (name = "serviceproviders" ) private list<serviceprovider> serviceproviders; @override public list<response> execute(request request) { return serviceproviders // 循環每個 service todo 現在時間復雜度為 o(n) 可以嘗試優化為 o(logn) .stream() .filter(serviceprovider -> serviceprovider.support(request)) // 按加工能力過濾 .map(serviceprovider -> serviceprovider.execute(request)) // 執行 service 得 execute 方法 .collect(collectors.tolist()); } } |
這里有一點需要解釋一下,在上面第二段代碼中,有這么一段:
1
2
|
@resource (name = "serviceproviders" ) private list<serviceprovider> serviceproviders; |
這里是使用 spring 中的 factorybean 機制實現的,可以簡單的這樣理解 factorybean :factorybean 是生成普通 bean 的 bean,當注入 factorybean 時,默認注入的是其生產出來的所有普通 bean,而不是它自己。
在上邊代碼中,注入的名為 serviceproviders 的這個 bean,實際上是這樣定義出來的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
@component ( "serviceproviders" ) // 注意這個 bean 的名字,當其他 bean 中注入這個 bean 時,會注入 createinstance() 返回類型的 bean,而不是其自身的類型 serviceproviderfactorybean public class serviceproviderfactorybean extends abstractfactorybean<list<serviceprovider>> implements applicationcontextaware { private applicationcontext applicationcontext; @override public class <?> getobjecttype() { return list. class ; } @override protected list<serviceprovider> createinstance() { // 掃描所有 provider 并從 bean 容器取出放入 list reflections reflections = new reflections(serviceprovider. class .getpackage().getname()); return reflections .getsubtypesof(serviceprovider. class ) .stream() .map((function< class <? extends serviceprovider>, serviceprovider>) serviceproviderclass -> applicationcontext.getbean(serviceproviderclass)) .collect(collectors.tolist()); } @override public void setapplicationcontext(applicationcontext applicationcontext) throws beansexception { this .applicationcontext = applicationcontext; } } |
通過這樣的設計,就完成了我們的需求,實際上我們等于把思路反轉了一下,從想盡辦法控制注入到不做控制,一股腦全部注入進去,然后按規則過濾。有時候,其實遇到一條思路走不通的時候,可以反過來想想,也許就會走通。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:https://since1986.github.io/blog/a9b7a8df.html