1.Spring 依賴注入
Spring框架的核心功能之一就是通過依賴注入的方式來管理Bean之間的依賴關(guān)系响禽。
依賴注入
每個(gè)基于應(yīng)用程序的 java 都有幾個(gè)對(duì)象躬它,這些對(duì)象一起工作來呈現(xiàn)出終端用戶所看到的工作的應(yīng)用程序。當(dāng)編寫一個(gè)復(fù)雜的 Java 應(yīng)用程序時(shí)滓技,應(yīng)用程序類應(yīng)該盡可能獨(dú)立于其他 Java 類來增加這些類重用的可能性哩牍,并且在做單元測(cè)試時(shí),測(cè)試獨(dú)立于其他類的獨(dú)立性令漂。依賴注入(或有時(shí)稱為布線)有助于把這些類粘合在一起膝昆,同時(shí)保持他們獨(dú)立。
假設(shè)你有一個(gè)包含文本編輯器組件的應(yīng)用程序叠必,并且你想要提供拼寫檢查荚孵。標(biāo)準(zhǔn)代碼看起來是這樣的:
在這里我們所做的就是創(chuàng)建一個(gè) TextEditor 和 SpellChecker 之間的依賴關(guān)系。在控制反轉(zhuǎn)的場(chǎng)景中纬朝,我們反而會(huì)做這樣的事情:
在這里收叶,TextEditor 不應(yīng)該擔(dān)心 SpellChecker 的實(shí)現(xiàn)。SpellChecker 將會(huì)獨(dú)立實(shí)現(xiàn)共苛,并且在 TextEditor 實(shí)例化的時(shí)候?qū)⑻峁┙o TextEditor判没,整個(gè)過程是由 Spring 框架的控制。
在這里隅茎,我們已經(jīng)從 TextEditor 中刪除了全面控制澄峰,并且把它保存到其他地方(即 XML 配置文件),且依賴關(guān)系(即 SpellChecker 類)通過類構(gòu)造函數(shù)被注入到 TextEditor 類中患膛。因此摊阀,控制流通過依賴注入(DI)已經(jīng)“反轉(zhuǎn)”,因?yàn)槟阋呀?jīng)有效地委托依賴關(guān)系到一些外部系統(tǒng)踪蹬。
依賴注入的第二種方法是通過 TextEditor 類的?Setter 方法胞此,我們將創(chuàng)建 SpellChecker 實(shí)例,該實(shí)例將被用于調(diào)用 setter 方法來初始化 TextEditor 的屬性跃捣。
因此漱牵,DI 主要有兩種變體和下面的兩個(gè)子章將結(jié)合實(shí)例涵蓋它們:
序號(hào)依賴注入類型 & 描述
1Constructor-based dependency injection
當(dāng)容器調(diào)用帶有多個(gè)參數(shù)的構(gòu)造函數(shù)類時(shí),實(shí)現(xiàn)基于構(gòu)造函數(shù)的 DI疚漆,每個(gè)代表在其他類中的一個(gè)依賴關(guān)系酣胀。
2Setter-based dependency injection
基于 setter 方法的 DI 是通過在調(diào)用無參數(shù)的構(gòu)造函數(shù)或無參數(shù)的靜態(tài)工廠方法實(shí)例化 bean 之后容器調(diào)用 beans 的 setter 方法來實(shí)現(xiàn)的。
你可以混合這兩種方法娶聘,基于構(gòu)造函數(shù)和基于 setter 方法的 DI闻镶,然而使用有強(qiáng)制性依存關(guān)系的構(gòu)造函數(shù)和有可選依賴關(guān)系的 sette r是一個(gè)好的做法。
代碼是 DI 原理的清洗機(jī)丸升,當(dāng)對(duì)象與它們的依賴關(guān)系被提供時(shí)铆农,解耦效果更明顯。對(duì)象不查找它的依賴關(guān)系狡耻,也不知道依賴關(guān)系的位置或類墩剖,而這一切都由 Spring 框架控制的猴凹。
2.Spring 基于構(gòu)造函數(shù)的依賴注入
Spring 基于構(gòu)造函數(shù)的依賴注入
當(dāng)容器調(diào)用帶有一組參數(shù)的類構(gòu)造函數(shù)時(shí),基于構(gòu)造函數(shù)的 DI 就完成了岭皂,其中每個(gè)參數(shù)代表一個(gè)對(duì)其他類的依賴郊霎。
接下來,我們將通過示例來理解 Spring?基于構(gòu)造函數(shù)的依賴注入爷绘。
示例:
下面的例子顯示了一個(gè)類 TextEditor书劝,只能用構(gòu)造函數(shù)注入來實(shí)現(xiàn)依賴注入。
讓我們用 Eclipse IDE 適當(dāng)?shù)毓ぷ魍林粒凑找韵虏襟E創(chuàng)建一個(gè) Spring 應(yīng)用程序庄撮。
步驟描述
1創(chuàng)建一個(gè)名為?SpringExample?的項(xiàng)目,并在創(chuàng)建的項(xiàng)目中的?src?文件夾下創(chuàng)建包?com.tutorialspoint?毙籽。
2使用?Add External JARs?選項(xiàng)添加必需的 Spring 庫(kù)洞斯,解釋見?Spring Hello World Example?chapter.
3在?com.tutorialspoint?包下創(chuàng)建 Java類?TextEditor,SpellChecker?和?MainApp坑赡。
4在?src?文件夾下創(chuàng)建 Beans 的配置文件?Beans.xml?烙如。
5最后一步是創(chuàng)建所有 Java 文件和 Bean 配置文件的內(nèi)容并按照如下所示的方法運(yùn)行應(yīng)用程序。
這是?TextEditor.java?文件的內(nèi)容:
下面是另一個(gè)依賴類文件?SpellChecker.java?的內(nèi)容:
以下是?MainApp.java?文件的內(nèi)容:
下面是配置文件?Beans.xml?的內(nèi)容毅否,它有基于構(gòu)造函數(shù)注入的配置:
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">? ? ? ? ? ? ? ? ?
當(dāng)你完成了創(chuàng)建源和 bean 配置文件后亚铁,讓我們開始運(yùn)行應(yīng)用程序。如果你的應(yīng)用程序運(yùn)行順利的話螟加,那么將會(huì)輸出下述所示消息:
Inside SpellChecker constructor.
Inside TextEditor constructor.
Inside checkSpelling.
構(gòu)造函數(shù)參數(shù)解析:
如果存在不止一個(gè)參數(shù)時(shí)徘溢,當(dāng)把參數(shù)傳遞給構(gòu)造函數(shù)時(shí),可能會(huì)存在歧義捆探。要解決這個(gè)問題然爆,那么構(gòu)造函數(shù)的參數(shù)在 bean 定義中的順序就是把這些參數(shù)提供給適當(dāng)?shù)臉?gòu)造函數(shù)的順序就可以了∈蛲迹考慮下面的類:
packagex.y;publicclassFoo{publicFoo(Bar bar, Baz baz){// ...}}
下述配置文件工作順利:
讓我們?cè)贆z查一下我們傳遞給構(gòu)造函數(shù)不同類型的位置曾雕。考慮下面的類:
packagex.y;publicclassFoo{publicFoo(intyear, String name){// ...}}
如果你使用 type 屬性顯式的指定了構(gòu)造函數(shù)參數(shù)的類型助被,容器也可以使用與簡(jiǎn)單類型匹配的類型剖张。例如:
最后并且也是最好的傳遞構(gòu)造函數(shù)參數(shù)的方式,使用 index 屬性來顯式的指定構(gòu)造函數(shù)參數(shù)的索引揩环。下面是基于索引為 0 的例子搔弄,如下所示:
最后,如果你想要向一個(gè)對(duì)象傳遞一個(gè)引用丰滑,你需要使用 標(biāo)簽的?ref?屬性顾犹,如果你想要直接傳遞值,那么你應(yīng)該使用如上所示的?value?屬性。
3.Spring 基于設(shè)值函數(shù)的依賴注入
Spring 基于設(shè)值函數(shù)的依賴注入
當(dāng)容器調(diào)用一個(gè)無參的構(gòu)造函數(shù)或一個(gè)無參的靜態(tài) factory 方法來初始化你的 bean 后蹦渣,通過容器在你的 bean 上調(diào)用設(shè)值函數(shù),基于設(shè)值函數(shù)的 DI 就完成了貌亭。
示例:
下述例子顯示了一個(gè)類?TextEditor柬唯,它只能使用純粹的基于設(shè)值函數(shù)的注入來實(shí)現(xiàn)依賴注入。
讓我們用 Eclipse IDE 適當(dāng)?shù)毓ぷ髌酝ィ凑找韵虏襟E創(chuàng)建一個(gè) Spring 應(yīng)用程序锄奢。
步驟描述
1創(chuàng)建一個(gè)名為?SpringExample?的項(xiàng)目,并在創(chuàng)建的項(xiàng)目中的?src?文件夾下創(chuàng)建包?com.tutorialspoint?剧腻。
2使用?Add External JARs?選項(xiàng)添加必需的 Spring 庫(kù)拘央,解釋見?Spring Hello World Example?chapter.
3在?com.tutorialspoint?包下創(chuàng)建 Java類?TextEditor,SpellChecker?和?MainApp书在。
4在?src?文件夾下創(chuàng)建 Beans 的配置文件?Beans.xml?灰伟。
5最后一步是創(chuàng)建所有 Java 文件和 Bean 配置文件的內(nèi)容并按照如下所示的方法運(yùn)行應(yīng)用程序。
下面是?TextEditor.java?文件的內(nèi)容:
在這里儒旬,你需要檢查設(shè)值函數(shù)方法的名稱轉(zhuǎn)換栏账。要設(shè)置一個(gè)變量?spellChecker,我們使用?setSpellChecker()?方法栈源,該方法與 Java POJO 類非常相似挡爵。讓我們創(chuàng)建另一個(gè)依賴類文件?SpellChecker.java?的內(nèi)容:
以下是?MainApp.java?文件的內(nèi)容:
下面是配置文件?Beans.xml?的內(nèi)容,該文件有基于設(shè)值函數(shù)注入的配置:
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">? ? ? ? ? ? ? ? ?
你應(yīng)該注意定義在基于構(gòu)造函數(shù)注入和基于設(shè)值函數(shù)注入中的 Beans.xml 文件的區(qū)別甚垦。唯一的區(qū)別就是在基于構(gòu)造函數(shù)注入中茶鹃,我們使用的是〈bean〉標(biāo)簽中的〈constructor-arg〉元素,而在基于設(shè)值函數(shù)的注入中艰亮,我們使用的是〈bean〉標(biāo)簽中的〈property〉元素闭翩。
第二個(gè)你需要注意的點(diǎn)是,如果你要把一個(gè)引用傳遞給一個(gè)對(duì)象迄埃,那么你需要使用 標(biāo)簽的?ref?屬性男杈,而如果你要直接傳遞一個(gè)值,那么你應(yīng)該使用?value?屬性调俘。
當(dāng)你完成了創(chuàng)建源和 bean 配置文件后伶棒,讓我們開始運(yùn)行應(yīng)用程序。如果你的應(yīng)用程序運(yùn)行順利的話彩库,那么將會(huì)輸出下述所示消息:
Inside SpellChecker constructor.
Inside setSpellChecker.
Inside checkSpelling.
使用 p-namespace 實(shí)現(xiàn) XML 配置:
如果你有許多的設(shè)值函數(shù)方法肤无,那么在 XML 配置文件中使用?p-namespace?是非常方便的。讓我們查看一下區(qū)別:
以帶有 標(biāo)簽的標(biāo)準(zhǔn) XML 配置文件為例:
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">? ? ? ? ? ? ? ? ? ? ? ? ?
上述 XML 配置文件可以使用?p-namespace?以一種更簡(jiǎn)潔的方式重寫骇钦,如下所示:
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">? ? ? ?
在這里宛渐,你不應(yīng)該區(qū)別指定原始值和帶有 p-namespace 的對(duì)象引用。-ref?部分表明這不是一個(gè)直接的值,而是對(duì)另一個(gè) bean 的引用窥翩。
4.Spring 注入內(nèi)部 Beans
注入內(nèi)部 Beans
正如你所知道的 Java 內(nèi)部類是在其他類的范圍內(nèi)被定義的业岁,同理,inner beans?是在其他 bean 的范圍內(nèi)定義的 bean寇蚊。因此在 或 元素內(nèi) 元素被稱為內(nèi)部bean笔时,如下所示。
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">? ? ? ? ? ? ? ? ? ? ? ?
例子
我們?cè)谶m當(dāng)?shù)奈恢檬褂?Eclipse IDE仗岸,然后按照下面的步驟來創(chuàng)建一個(gè) Spring 應(yīng)用程序:
步驟描述
1創(chuàng)建一個(gè)名稱為?SpringExample?的項(xiàng)目允耿,并且在創(chuàng)建項(xiàng)目的?src?文件夾中創(chuàng)建一個(gè)包?com.tutorialspoint?。
2使用?Add External JARs?選項(xiàng)扒怖,添加所需的 Spring 庫(kù)较锡,解釋見?Spring Hello World Example?章節(jié)。 option as explained in the chapter.
3在?com.tutorialspoint?包中創(chuàng)建Java類TextEditor盗痒、SpellChecker?和?MainApp蚂蕴。
4在?src?文件夾中創(chuàng)建 Beans 配置文件?Beans.xml。
5最后一步是創(chuàng)建的所有Java文件和Bean配置文件的內(nèi)容俯邓,并運(yùn)行應(yīng)用程序掂墓,解釋如下所示。
這里是?TextEditor.java?文件的內(nèi)容:
下面是另一個(gè)依賴的類文件?SpellChecker.java?內(nèi)容:
下面是?MainApp.java?文件的內(nèi)容:
下面是使用內(nèi)部 bean?為基于 setter 注入進(jìn)行配置的配置文件?Beans.xml?文件:
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">? ? ? ? ? ? ? ? ? ? ? ? ?
一旦你創(chuàng)建源代碼和 bean 配置文件完成后看成,我們就可以運(yùn)行該應(yīng)用程序君编。如果你的應(yīng)用程序一切都正常,將輸出以下信息:
Inside SpellChecker constructor.
Inside setSpellChecker.
Inside checkSpelling.
5.Spring 注入集合
注入集合
你已經(jīng)看到了如何使用?value?屬性來配置基本數(shù)據(jù)類型和在你的 bean 配置文件中使用<property>標(biāo)簽的?ref?屬性來配置對(duì)象引用川慌。這兩種情況下處理奇異值傳遞給一個(gè) bean吃嘿。
現(xiàn)在如果你想傳遞多個(gè)值,如 Java Collection 類型 List梦重、Set兑燥、Map 和 Properties,應(yīng)該怎么做呢琴拧。為了處理這種情況降瞳,Spring 提供了四種類型的集合的配置元素,如下所示:
元素描述
<list>它有助于連線蚓胸,如注入一列值挣饥,允許重復(fù)。
<set>它有助于連線一組值沛膳,但不能重復(fù)扔枫。
<map>它可以用來注入名稱-值對(duì)的集合,其中名稱和值可以是任何類型锹安。
<props>它可以用來注入名稱-值對(duì)的集合短荐,其中名稱和值都是字符串類型倚舀。
你可以使用<list>或<set>來連接任何?java.util.Collection?的實(shí)現(xiàn)或數(shù)組。
你會(huì)遇到兩種情況(a)傳遞集合中直接的值(b)傳遞一個(gè) bean 的引用作為集合的元素忍宋。
例子
我們?cè)谶m當(dāng)?shù)奈恢檬褂?Eclipse IDE痕貌,然后按照下面的步驟來創(chuàng)建一個(gè) Spring 應(yīng)用程序:
步驟描述
1創(chuàng)建一個(gè)名稱為?SpringExample?的項(xiàng)目,并且在創(chuàng)建項(xiàng)目的?src?文件夾中創(chuàng)建一個(gè)包?com.tutorialspoint?糠排。
2使用?Add External JARs?選項(xiàng)舵稠,添加所需的 Spring 庫(kù),解釋見?Spring Hello World Example?章節(jié)乳讥。 option as explained in the chapter.
3在?com.tutorialspoint?包中創(chuàng)建Java類TextEditor、SpellChecker?和?MainApp廓俭。
4在?src?文件夾中創(chuàng)建 Beans 配置文件?Beans.xml云石。
5最后一步是創(chuàng)建的所有Java文件和Bean配置文件的內(nèi)容,并運(yùn)行應(yīng)用程序研乒,解釋如下所示汹忠。
這里是?JavaCollection.java?文件的內(nèi)容:
下面是?MainApp.java?文件的內(nèi)容:
下面是配置所有類型的集合的配置文件?Beans.xml?文件:
<?xml version="1.0"encoding="UTF-8"?>
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><!-- Definition for javaCollection --><!-- results in a setAddressList(java.util.List) call -->INDIAPakistanUSAUSA<!-- results in a setAddressSet(java.util.Set) call -->INDIAPakistanUSAUSA<!-- results in a setAddressMap(java.util.Map) call --><!-- results in a setAddressProp(java.util.Properties) call -->INDIAPakistanUSAUSA
一旦你創(chuàng)建源代碼和 bean 配置文件完成后,我們就可以運(yùn)行該應(yīng)用程序雹熬。你應(yīng)該注意這里不需要配置文件宽菜。如果你的應(yīng)用程序一切都正常,將輸出以下信息:
List Elements :[INDIA, Pakistan, USA, USA]
Set Elements :[INDIA, Pakistan, USA]
Map Elements :{1=INDIA, 2=Pakistan, 3=USA, 4=USA}
Property Elements :{two=Pakistan, one=INDIA, three=USA, four=USA}
注入 Bean 引用
下面的 Bean 定義將幫助你理解如何注入 bean 的引用作為集合的元素竿报。甚至你可以將引用和值混合在一起铅乡,如下所示:
<?xml version="1.0"encoding="UTF-8"?>
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><!-- Bean Definition to handle references and values --><!-- Passing bean reference? for java.util.List -->Pakistan<!-- Passing bean reference? for java.util.Set -->Pakistan<!-- Passing bean reference? for java.util.Map -->
為了使用上面的 bean 定義,你需要定義 setter 方法烈菌,它們應(yīng)該也能夠是用這種方式來處理引用阵幸。
注入 null 和空字符串的值
如果你需要傳遞一個(gè)空字符串作為值,那么你可以傳遞它芽世,如下所示:
前面的例子相當(dāng)于 Java 代碼:exampleBean.setEmail("")挚赊。
如果你需要傳遞一個(gè) NULL 值,那么你可以傳遞它济瓢,如下所示:
前面的例子相當(dāng)于 Java 代碼:exampleBean.setEmail(null)荠割。