前言
在前面的文章里,Maven底層容器Plexus Container的前世今生,一代芳華終落幕怀各,我們提到幅垮,在Plexus Container退任后岭接,取而代之的底層容器是Guice冕末。
Guice的應(yīng)用也還比較廣泛,以下輪子中(僅部分)都有它活躍的身影:
- google內(nèi)部
- scalatest
- TestNG
- Caffeine Cache
- Spring Security Config
- elastic search
- jenkins
這很多輪子,都是直接用的Guice坟乾,那是因為沒什么歷史包袱迹辐;但Maven不一樣,maven之前用自己的IOC輪子甚侣,有自己獨特的定義組件的方式(比如Spring通過@Component注解來定義)明吩;但是Guice作為一個獨立的IOC框架,那肯定是不認(rèn)識Maven中的組件的殷费。
因此印荔,這中間肯定需要兼容啊,Maven的組件详羡,還是用的Plexus IOC容器那套方式去定義仍律,但是他們開發(fā)了一個中間層,把那些組件解析后实柠,存放到了Guice容器中水泉。
這里說,把組件解析后窒盐,存放到了Guice容器中草则,這個也不是特別準(zhǔn)確,更準(zhǔn)確的說法是蟹漓,放到了基于Guice進(jìn)行了一層封裝的一個容器中畔师,這個容器叫做:sisu,由eclipse在維護(hù)這個開源項目(https://www.eclipse.org/sisu/)牧牢。
可能你就疑惑了,就一個破IOC姿锭,搞得多有技術(shù)含量一樣塔鳍,還一層套一層。呻此。這個我們就先不管了轮纫,這期我先講Guice,然后大家就懂了焚鲜,為啥Sisu要要封裝一層了掌唾。總結(jié)一下忿磅,依賴路徑是:
最底層的是google Guice --》 sisu(eclipse)--》 sisu-plexus兼容層--》plexus --》maven糯彬。
好了,開始正文葱她。
Guice是什么
根據(jù)wiki的描述撩扒,Guice就是依賴注入框架,由google開源吨些。主要特點就是:支持以java注解的方式配置組件及依賴搓谆。最早的版本應(yīng)該是在2007年炒辉,我還找到一篇當(dāng)年的報道 https://developers.googleblog.com/2007/03/,
當(dāng)時還是2007年泉手,而2004年的時候黔寇,支持注解的JDK1.5才放出來,與此同時斩萌,Spring早期版本主要也還是以xml配置為主缝裤,Guice在那時就支持全注解配置,以當(dāng)時的眼光來看术裸,很前沿了倘是。
接下來,我們就來仔細(xì)了解下Guice的用法袭艺。
核心理念
在開始講之前搀崭,我說下我對IOC框架的理解先。很多時候猾编,可以簡單地說瘤睹,IOC容器是一個map,一個放東西的地方答倡,就像一個中藥房轰传,每個格子里會放一種藥材,而每個格子上瘪撇,有一個標(biāo)簽获茬,來說明里面放的是什么藥材。
既然是放東西的地方倔既,核心就是兩個部分恕曲,怎么放,放的時候渤涌,可能就要考慮到后續(xù)怎么找的問題佩谣。比如,如果你打算只支持根據(jù)物品的類型來找实蓬,那你要考慮到:如果這個類型的物品有多個茸俭,要怎么辦?怎么區(qū)分這多個物品安皱?
如果你打算解決這個問題调鬓,那你可能就會想:那我放的時候,再給這些物品取個名字吧酌伊,免得多個相同類型的物品袖迎,分不清。
甚至呢,你可能會考慮燕锥,物品的權(quán)限隔離辜贵,比如,物品上再加個存放人的字段归形,以后取得時候托慨,就只能:自己取自己的,不能取別人的暇榴。
反正厚棵,最終還是看需求,一般來說蔼紧,像我們spring這種婆硬,按類型就差不多了,一個類型多個實現(xiàn)的時候奸例,再根據(jù)名字區(qū)分一下就ok彬犯。
而Guice呢,我這邊會重點講解:怎么存查吊。至于取谐区,可能還分成兩種,依賴注入和直接從容器中取逻卖。但是依賴注入的底層實現(xiàn)宋列,也是:發(fā)現(xiàn)我依賴的某個東西沒有,就去容器里取评也。
所以炼杖,取東西,我們只需要關(guān)注:直接從容器中怎么獲取就行盗迟;我這邊就不會特別關(guān)注依賴注入的問題嘹叫。
Guice中,存東西的多種方式
概覽
存東西诈乒,在Guice的文檔里,名詞叫做Binding婆芦,中文就是綁定吧怕磨。
https://github.com/google/guice/wiki/Bindings
綁定是什么意思,就是我最終可能需要從容器中獲取ClassA類型的對象消约。既然要取肠鲫,那還得先存,存的時候或粮,我就要建立綁定:ClassA --》該Class類型對象的獲取方式导饲。
其實還是很簡單的。下邊就跟著我的代碼例子,我們來看看渣锦。
以下全部的代碼硝岗,都在:
https://gitee.com/ckl111/maven-3.8.1-source-learn/tree/master/my-test-modules/official-guice-demo
1. linkedbinding-綁定接口到實現(xiàn)類
先來一個接口和實現(xiàn):
public interface HelloInterface {
void hello();
}
public class HelloInterfaceImpl implements HelloInterface {
@Override
public void hello() {
System.out.println("hello world");
}
}
再來看看,怎么放到容器袋毙,和簡單的從容器中取出來的方法:
大家看我代碼截圖型檀,放東西的時候,就是要指定這個接口听盖,對應(yīng)的實現(xiàn)類胀溺。
取東西的時候,再去根據(jù)接口取就行了皆看。
2.BindingAnnotations 一個類型有多個實現(xiàn)類的時候的綁定方式
接口和多個實現(xiàn)類:
interface HelloInterface {
void hello();
}
class HelloInterfaceImpl implements HelloInterface {
@Override
public void hello() {
System.out.println("hello world");
}
}
class HelloInterfaceImpl2 implements HelloInterface {
@Override
public void hello() {
System.out.println("hello world");
}
}
如果我們還是按前面的辦法去取仓坞,框架就暈圈了,多個實現(xiàn)類腰吟,我給你哪一個呢无埃?麻煩再明確一下吧,ok嗎
Guice有個注解蝎困,叫Named录语,可以加在各種地方,注解本身禾乘,支持設(shè)置名稱澎埠。
這里意思就是說,你接口不是多個實現(xiàn)嗎始藕,那我們這樣:接口+注解蒲稳,才算是唯一的key,這樣ok了吧伍派。
因此江耀,現(xiàn)在就變成了這樣:接口+注解1 --》 實現(xiàn)類1;接口 + 注解2 --》 實現(xiàn)類2.
那我怎么取呢诉植?簡單啊祥国,怎么存,怎么取晾腔,存的時候舌稀,用的接口+注解,取的時候灼擂,也需要這樣壁查。
既然,可以用官方的Named注解剔应,那其實自己的注解也一樣可以用睡腿。
3. InstanceBindings 接口直接綁定一個單例對象
如果同一個類型语御,要綁定到多個實例的情況,同前面的處理方式一樣席怪。
4. 綁定到工廠方法:授人以魚不如授人以漁
前面都是些直來直去的辦法应闯,這次不一樣,我只告訴你何恶,這個東西的獲得方法孽锥。
5. 不用接口了,直接綁定一個實現(xiàn)類
前面都是根據(jù)一個接口類细层,去取接口對應(yīng)的實現(xiàn)之類的惜辑。這次不一樣,直接就是一個實現(xiàn)類了疫赎。
public class UtilService {
}
像上面這個情況盛撑,那肯定是直接調(diào)用這個類的構(gòu)造函數(shù)了。
6. 接口綁定到一個構(gòu)造函數(shù):ToConstructorBindings
哎捧搞,我是越來越無語了抵卫,Guice的騷操作真是多啊。
7. 內(nèi)置的不用綁就能用的
主要有:Logger胎撇、Injector本身(就是相當(dāng)于可以幫你注入容器自身)
8. 能不能不綁定直接用
用慣了spring的我們介粘,現(xiàn)在已經(jīng)是不需要這么綁來綁去了。我們看看Guice的支持怎么樣
不綁定的話晚树,可以這樣:
@ImplementedBy(TestInterfaceImpl.class)
interface TestInterface {
}
這就相當(dāng)于姻采,你要自己指定一下,你的實現(xiàn)類是誰爵憎,或者你的provider是誰慨亲。但是官方不建議用這種隱式綁定,不知道為啥宝鼓,還出了個選項刑棵,專門禁用隱式綁定。
9. 一個接口多個實現(xiàn)類愚铡,一次性全獲取回來
這個場景蛉签,就是一次性把多實現(xiàn)類一把取回來,放到一個集合里給你沥寥。
這個場景我沒寫代碼碍舍,大家自己看一下文檔,也簡單营曼。
10. 注入的方式
前面說了很多怎么手動從容器里面取,當(dāng)然了愚隧,要自動注入的話蒂阱,也是支持:構(gòu)造器注入锻全、field注入等等方式。
如以下為構(gòu)造器注入:其他支持的特性
其他的录煤,比如循環(huán)依賴鳄厌、aop也是大體支持的,只是這個容器在安卓端用妈踊,會有問題了嚎,因為aop好像不太支持,所以給安卓端還專供了一個去掉aop的版本廊营。
循環(huán)依賴之類的歪泳,具體實現(xiàn)還沒怎么看過。
另外露筒,guice默認(rèn)生成的是多例(類比spring的prototype呐伞,而不是singleton),但是本身也是支持singleton的慎式,我前面的代碼例子有伶氢。
最大槽點
可以看出,Guice是很輕量瘪吏,輕量的意思是癣防,功能沒Spring那么全,所以掌眠,我們還需要去顯式地:配置每個接口蕾盯,要怎么獲取它的對象(方法也是五花八門,哈哈哈扇救,如前面展示的)刑枝。
當(dāng)然,配置ok后迅腔,我們獲取某對象的時候装畅,它會幫我們?nèi)ネ瓿勺詣幼⑷氲臇|西。
但是沧烈,它也不支持類路徑掃描啊掠兄,比如給個包名,自動去掃描這個包下面的組件锌雀,反正官方不支持蚂夕,說是有第三方插件,還沒試過腋逆。
總結(jié)
在各種輪子里婿牍,用來管理自己的代碼間的相互依賴,用Guice確實足夠了惩歉,用在業(yè)務(wù)代碼等脂,就還是有點累俏蛮。
因為,主要是:各種依賴要自己配上遥,只是集中在一個地方配置而已搏屑,沒有像spring那樣,約定通過接口找對象時粉楚,默認(rèn)就是找實現(xiàn)類辣恋,然后反射生成對象。
這一點來說模软,確實是:約定優(yōu)于配置伟骨,就像Maven為啥打敗了ant,也是這個道理撵摆。
另外的問題就是底靠,不支持spring的那種component-scan。
基于這兩個問題呢特铝,方法肯定是有的暑中,所以,Maven也足夠聰明鲫剿,沒有直接基于Guice鳄逾,而是選擇了基于Guice封裝后的Sisu,而Sisu就可以解決我們說的問題灵莲,支持類路徑掃描之類的雕凹。
我們看看sisu怎么介紹自己:
就是比Guice多了些看起來還很不錯的、Spring早已有了的特性吧政冻∶兜郑回頭我們肯定要再介紹sisu的。
再見明场,以上汽摹。
本文由博客一文多發(fā)平臺 OpenWrite 發(fā)布!