依賴注入(Dependency Injection)的意思就是對象通過構(gòu)造器函數(shù)參數(shù),工廠方法的參數(shù),或者成員屬性,定義了對象的依賴對象;容器在創(chuàng)建該對象時會負(fù)責(zé)注入這些依賴。這個過程是控制反轉(zhuǎn)的,即不是由即將創(chuàng)建的對象來管理自己的依賴的發(fā)現(xiàn)和實(shí)例化,而是有Spring容器來實(shí)現(xiàn)。
巴宜網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營維護(hù)。創(chuàng)新互聯(lián)2013年至今到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
在Spring中依賴注入有兩種形式,第一種就是基于構(gòu)造函數(shù)的注入,即通過調(diào)用構(gòu)造函數(shù),傳入?yún)?shù),也就是依賴來完成整個依賴注入流程;第二種就是基于setter方法的注入。
構(gòu)造函數(shù)的參數(shù)的匹配,要避免歧義,如指定類型,指定參數(shù)的次序等。如果是按照參數(shù)名字匹配,則必須開啟debug模式進(jìn)行編譯,否則參數(shù)名字是不保留的。如果不想開啟debug模式編譯,則可以使用@ConstructorProperties注解。
setter方法注入是先調(diào)用沒有參數(shù)的默認(rèn)構(gòu)造函數(shù)構(gòu)建對象,或者沒有參數(shù)的靜態(tài)工廠方法,實(shí)例化bean后,調(diào)用setter方法來將該對象注入。
通過使用依賴注入,可以使代碼更簡潔,更好地實(shí)現(xiàn)對象之間解耦。另外,通過依賴注入管理的的對象是POJO類,可以更好地進(jìn)行測試。
最佳實(shí)踐是通過構(gòu)造器方法注入主要依賴對象,通過setter方法注入可選的依賴對象。雖然可以在setter方法上加上@Required注解來實(shí)現(xiàn)主要依賴對象注入,但一般還是推薦使用構(gòu)造器注入必須的依賴。
使用構(gòu)造器注入,可以使得應(yīng)用的組件作為不可變的對象,而且可以保證注入依賴是非null的。另外,構(gòu)造器注入返回的是一個完整的初始狀態(tài)的實(shí)例。但是,一般不推薦大量使用構(gòu)造方法注入,如果出現(xiàn)這種情況,則說明代碼需要重構(gòu)。
setter方法適合注入可選的依賴,這些依賴可能有默認(rèn)值,而且在其他位置使用這些依賴時務(wù)必要進(jìn)行null值檢查。使用setter方法的一個好處是可以修改或者重新配置,或者需要時再注入。如基于JMX MBean的管理。
首先ApplicationContext會被創(chuàng)建和初始化,會加載包括描述所有bean的元數(shù)據(jù)。這些配置元數(shù)據(jù)可以通過XML,Java代碼或者注解來指定。
對于每一個bean,它的依賴表現(xiàn)形式是成員屬性,構(gòu)造器參數(shù),或者靜態(tài)工廠方法的參數(shù)。在bean真正創(chuàng)建時,Spring容器會提供這些依賴的對象。這些參數(shù)可能是需要設(shè)置的默認(rèn)值,也可能是另外一個bean的引用。
Spring容器會驗(yàn)證每個bean的配置信息。并且在bean真正創(chuàng)建時才設(shè)置設(shè)置屬性值或者參數(shù)值。
在Spring中,單例作用域的bean會提前初始化,在Spring容器創(chuàng)建時就進(jìn)行了實(shí)例化。對于其他的作用域的bean,則只在需要時才進(jìn)行創(chuàng)建。之所以單例作用域的bean會被提前初始化,主要是為了解決依賴檢查的問題,下文的循環(huán)依賴一節(jié)會詳細(xì)說明。
在Spring內(nèi)部會構(gòu)建一個創(chuàng)建bean的依賴圖,按照這依賴關(guān)系來創(chuàng)建Bean。
如果使用構(gòu)造函數(shù)注入,則不能有循環(huán)依賴的情況。如A構(gòu)造器依賴B,同時B也構(gòu)造器依賴A。Spring IoC容器會在運(yùn)行時檢測到循環(huán)依賴,拋BeanCurrentlyInCreationException異常。一種解決辦法是通過setter方法來解決循環(huán)依賴的情況。
Spring會在容器加載時檢測配置問題,如引用不存在或者循環(huán)依賴。Spring會在必要時才解析依賴,即盡可能晚的來解析依賴關(guān)系。延遲解析依賴可能導(dǎo)致后期請求獲取對象時報(bào)錯,如拋出一個異常,如丟失指定對象或者屬性。這種配置的延遲的可見性導(dǎo)致的問題使得ApplicationContext的實(shí)現(xiàn)要求單例作用域的bean提前記性初始化。雖然會耗費(fèi)內(nèi)存和時間,因?yàn)椴⒉皇前葱鑴?chuàng)建這些單例作用域的bean,但是可以在ApplicationContext創(chuàng)建時就可以發(fā)現(xiàn)配置問題。
下文會介紹通過指定bean的可以通過配置來覆蓋默認(rèn)的行為,使得單例作用域的bean也是延遲初始化。
如果沒有循環(huán)依賴存在,則在注入依賴對象時,這些依賴的對象就已經(jīng)初始化完成了。即如果A依賴B,則在A初始化時,B已經(jīng)初始化完成了。也就是說,Bean是在相關(guān)依賴設(shè)置完成,并且相關(guān)的生命周期方法調(diào)用完畢后,才算是完成了初始化。
默認(rèn)情況下ApplicationContext是提前初始化單例作用域的bean,作為ApplicationContext初始化的一部分。這樣可以盡快的發(fā)現(xiàn)配置問題。可以通過指定bean的lazy-init="true",讓bean在需要時才被初始化。
在Spring中可以自動注入依賴,可以減少指定屬性或者構(gòu)造器參數(shù),還可以隨著配置對象的變化來更新注入的對象。
自動注入依賴的模式有:通過名稱注入,通過類型注入,和通過構(gòu)造器注入。
本文總結(jié)了Spring中的依賴管理的基本原理和常見的問題,具體的依賴注入配置語法還需要參考Spring的官方文檔來進(jìn)行。
針對于上面所涉及到的知識點(diǎn)我總結(jié)出了有1到5年開發(fā)經(jīng)驗(yàn)的程序員在面試中涉及到的絕大部分架構(gòu)面試題及答案做成了文檔和架構(gòu)視頻資料免費(fèi)分享給大家(包括Dubbo、redis、Netty、zookeeper、Spring cloud、分布式、高并發(fā)等架構(gòu)技術(shù)資料),希望能幫助到您面試前的復(fù)習(xí)且找到一個好的工作,也節(jié)省大家在網(wǎng)上搜索資料的時間來學(xué)習(xí),也可以關(guān)注我一下以后會有更多干貨分享。