Field injection is not recommended – Spring IOC & Spring 三種依賴注入方式

運(yùn)行 IDE 的自動(dòng)檢查工具分析代碼時(shí), 如果用@Autowired 注解的話,會(huì)提示如下的警告:


FieldInjectionIsNotRecommended.png

第一次看到這樣的提示,是很困惑的墩弯,因?yàn)橥ǔG闆r下直接使用@Autowired 不僅讓代碼更加簡(jiǎn)潔易讀吩跋,寫起來也十分的方便。

雖然最新(5.1.9)的Spring 文檔依賴注入的章節(jié)里只介紹了兩種依賴注入的方法渔工,但實(shí)際上有三種依賴注入的方式:

  1. Constructor-based dependency injection(基于構(gòu)造方法的依賴注入)
  2. Setter-based dependency injection(基于 setter 的依賴注入)
  3. Field-based dependency injection(基于 filed 注解的依賴注入)

第三種依賴注入的方式是代碼分析工具不建議的锌钮,但也是使用最多、最常見的依賴注入方式引矩。即使在 Spring 官方的一些手冊(cè)里(比如Accessing data with MySQL)梁丘,也可以看到使用 Field-based dependency injection。

下面分別具體介紹一下這三種依賴注入的方式旺韭。

三種依賴注入的方式

  • Constructor-based dependency injection

    @Component
    public class ConstructorBasedInjection {
    
        private final InjectedBean injectedBean;
    
        @Autowired
        public ConstructorBasedInjection(InjectedBean injectedBean) {
            this.injectedBean = injectedBean;
        }
    
    }
    

    基于構(gòu)造方法的依賴注入的主要優(yōu)點(diǎn)是氛谜,可以注入聲明為 final 的字段。
    基于構(gòu)造方法的依賴注入在類實(shí)例化期間啟動(dòng)区端,對(duì)于必要的依賴項(xiàng)來說值漫,使用構(gòu)造方法注入會(huì)更合適。

  • Setter-based dependency injection

    @Component
    public class ConstructorBasedInjection {
    
        private InjectedBean injectedBean;
    
        @Autowired
        public void setInjectedBean(InjectedBean injectedBean) {
            this.injectedBean = injectedBean;
        }
    
    }
    

    如果使用無參數(shù)構(gòu)造方法或無參數(shù)靜態(tài)工廠方法實(shí)例化 Bean织盼,Spring 容器將調(diào)用這些 setter 方法杨何,注入 Bean 的依賴項(xiàng)。

  • Field-based dependency injection

    @Component
    public class ConstructorBasedInjection {
    
        @Autowired
        private InjectedBean injectedBean;
    
    }
    

    使用基于字段的依賴注入的話沥邻,只需在需要注入的字段加上@Autowired危虱,Spring 容器就會(huì)在類初始化的時(shí)候設(shè)置這些字段。
    可以看到谋国,這種方法確實(shí)是最簡(jiǎn)潔的,不需要任何模版代碼迁沫。但是為什么代碼檢查還是還是不建議這種方法呢芦瘾?因?yàn)樗_實(shí)存在著一些缺點(diǎn)。

Field-based dependency injection 的缺點(diǎn)

  • 不允許 Immutable 字段的聲明

    基于字段的依賴注入不支持聲明為 final 的字段集畅,聲明為 final 的字段必須在類初始化的時(shí)候初始化該字段近弟。如果聲明了 final 的字段并想注入該依賴,唯一的方式是使用基于構(gòu)造方法的注入

  • 可能會(huì)違反單一職責(zé)原則

    在面向?qū)ο蟮脑O(shè)計(jì)原則中挺智,我們經(jīng)常會(huì)提到 SOLID祷愉,更好地遵循 SOLID 原則能讓我們的代碼更好理解、維護(hù)赦颇,拓展性更強(qiáng)二鳄。其中 S 指的是單一職責(zé)原則,也就是一個(gè)類應(yīng)該只負(fù)責(zé)整個(gè)工程的單個(gè)功能部分媒怯。

    如果使用基于字段依賴注入的話订讼,即使這個(gè)類依賴了很多其它的類,也經(jīng)常覺得沒什么問題扇苞。而如果使用基于構(gòu)造方法的依賴注入的話欺殿,會(huì)很容易發(fā)現(xiàn)構(gòu)造方法傳入了太多的參數(shù)(有的人覺得這是基于構(gòu)造方法依賴注入方法的缺點(diǎn)寄纵,事實(shí)上出現(xiàn)這種情況時(shí),是一個(gè)代碼需要重構(gòu)的提醒)脖苏,這個(gè)時(shí)候我們可以審視我們的代碼程拭,是否需要將該類拆分重構(gòu)。

    使用基于字段的依賴注入雖然沒有直接違背單一職責(zé)原則棍潘,但確實(shí)隱藏了發(fā)現(xiàn)違背單一職責(zé)原則的一些信號(hào)恃鞋。

  • 與依賴注入的結(jié)合過分緊密

    使用基于字段的依賴注入的主要原因是能夠減少代碼,讓代碼簡(jiǎn)潔蜒谤。但這同時(shí)也意味著設(shè)置這些字段的唯一方法是通過 Spring 容器實(shí)例化類并使用反射注入它們山宾,否則字段將不會(huì)初始化,該類也無法使用鳍徽。

    如果要在 Spring 容器外部使用這些類资锰,比如單元測(cè)試,則必須使用 Spring 容器來實(shí)例化類阶祭,沒有其他方法(除了反射)來設(shè)置這些字段绷杜。
    而如果使用基于構(gòu)造方法或者基于 setter 依賴注入時(shí),在單元測(cè)試時(shí)濒募,我們可以 mock 依賴的對(duì)象鞭盟,并將它們傳到構(gòu)造方法或 setter 方法中,會(huì)讓單元測(cè)試簡(jiǎn)單很多瑰剃。

  • 隱藏了依賴關(guān)系

    使用基于構(gòu)造方法依賴注入齿诉,或者基于 setter 的依賴注入時(shí),外部可以通過構(gòu)造方法或者 setter 方法知道該類的依賴項(xiàng)晌姚。
    而如果使用基于字段的依賴注入時(shí)粤剧,該類的所有依賴對(duì)于外部來說是不可知的。

結(jié)論

基于字段的依賴注入雖然用起來十分方便挥唠,代碼也十分簡(jiǎn)潔抵恋,但確實(shí)存在著一些缺點(diǎn),這也是為什么代碼檢查工具不推薦這種寫法的原因宝磨。
通常情況下弧关,如果有 final 字段,或者有必需的依賴項(xiàng)唤锉,建議使用基于構(gòu)造方法的依賴注入世囊。基于 setter 的依賴注入通常建議用來注入可選的依賴項(xiàng)窿祥。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末茸习,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子壁肋,更是在濱河造成了極大的恐慌号胚,老刑警劉巖籽慢,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異猫胁,居然都是意外死亡箱亿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門弃秆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來届惋,“玉大人,你說我怎么就攤上這事菠赚∧员” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵衡查,是天一觀的道長(zhǎng)瘩欺。 經(jīng)常有香客問我,道長(zhǎng)拌牲,這世上最難降的妖魔是什么俱饿? 我笑而不...
    開封第一講書人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮塌忽,結(jié)果婚禮上拍埠,老公的妹妹穿的比我還像新娘。我一直安慰自己土居,他們只是感情好枣购,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著擦耀,像睡著了一般棉圈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上埂奈,一...
    開封第一講書人閱讀 51,274評(píng)論 1 300
  • 那天迄损,我揣著相機(jī)與錄音定躏,去河邊找鬼账磺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛痊远,可吹牛的內(nèi)容都是我干的垮抗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼碧聪,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼冒版!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起逞姿,我...
    開封第一講書人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤辞嗡,失蹤者是張志新(化名)和其女友劉穎捆等,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體续室,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡栋烤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挺狰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片明郭。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖丰泊,靈堂內(nèi)的尸體忽然破棺而出薯定,到底是詐尸還是另有隱情,我是刑警寧澤瞳购,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布话侄,位于F島的核電站,受9級(jí)特大地震影響苛败,放射性物質(zhì)發(fā)生泄漏满葛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一罢屈、第九天 我趴在偏房一處隱蔽的房頂上張望嘀韧。 院中可真熱鬧,春花似錦缠捌、人聲如沸锄贷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)谊却。三九已至,卻和暖如春哑芹,著一層夾襖步出監(jiān)牢的瞬間炎辨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工聪姿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碴萧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓末购,卻偏偏與公主長(zhǎng)得像破喻,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子盟榴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容