天天看點

Spring(03)——依賴注入3依賴注入

<code>Spring bean</code>的依賴注入有兩種形式,通過構造方法注入和通過<code>set</code>方法注入。構造方法注入是通過<code>constructor-arg</code>元素來指定的,而<code>set</code>方法注入是通過<code>property</code>元素來指定的。

先來看一個簡單的示例:

上述配置定義了一個類型為<code>com.app.Hello</code>的<code>bean</code>,我們通過<code>constructor-arg</code>指定了其第一個構造參數的值為字元串<code>“hello”</code>,這就是一個簡單的通過構造方法進行注入的示例。

當參數類型為基本資料類型時可以直接通過<code>constructor-arg</code>元素的<code>value</code>屬性指定對應的值,更确切的講應該是<code>Spring</code>能夠通過<code>String</code>進行轉換的類型,預設<code>Spring</code>能将<code>String</code>轉換成對應的基本資料類型,其它的需要自己指定轉換規則了。如上面示例中的<code>value=”hello”</code>就是這樣的。

當有多個構造參數時就需要使用多個<code>constructor-arg</code>進行定義,預設會将定義的順序作為參數的順序。

如上<code>Class</code>,我們在定義對應的<code>bean</code>時可以如下定義,這個時候預設會按照定義的順序将第一個參數指派給構造方法的第一個參數,第二個給第二個,第n個給第n個。

當然,我們也可以明确的利用<code>index</code>來指定<code>constructor-arg</code>對應參數的位置,<code>index</code>是從0開始的,即第一個參數對應的<code>index</code>為0。使用<code>index</code>時,<code>Hello</code>對應的<code>bean</code>可以如下定義。

當構造參數對應于<code>ApplicationContext</code>中的一個<code>bean</code>時,我們也可以通過<code>ref</code>屬性關聯對應的<code>bean</code>,即注入的不再是普通的字元串,而是對應的<code>bean</code>。

我們還可以通過<code>constructor-arg</code>元素的<code>name</code>屬性來指定對應<code>constructor-arg</code>對應的參數,如:

但是這需要我們的<code>class</code>是通過<code>debug</code>方式進行編譯的,這樣<code>Spring</code>才能識别出對應的參數名稱。當然我們也可以通過<code>JDK</code>提供的<code>@ConstructorProperties</code>注解來指定構造參數對應的名稱。如:

當我們的構造參數比較複雜,比如是一個<code>array、list、set、map</code>等或者需要定義一個内部的<code>bean</code>時,我們可以直接在<code>constructor-arg</code>元素中間進行定義,如:

<code>set</code>方法注入是通過<code>property</code>元素定義的。定義時我們需要指定<code>property</code>元素的<code>name</code>屬性,其對應的值并非<code>bean</code>需要進行注入的屬性名稱,而是對應<code>set</code>方法去掉<code>set</code>字首後首字母小寫的結果。

對于上述<code>class</code>定義,如果現在我們需要定義對應的<code>bean</code>,并通過<code>setProp()</code>方法将字元串<code>“Value”</code>注入給其私有屬性<code>prop1</code>,那麼我們的<code>bean</code>應該如下定義:

在上述示例中<code>property</code>元素對應的語義是<code>setProp(“value”)</code>,即我們的注入雖然是通過<code>property</code>元素進行的,但其不是通過<code>bean</code>的某屬性進行注入的,而是通過對應的<code>set</code>方法進行注入的。

對于基本資料類型值我們可以直接通過<code>property</code>元素的<code>value</code>屬性進行注入,如果需要注入其它<code>bean</code>,我們可以通過在<code>property</code>元素下定義<code>ref</code>元素進行引用或者通過<code>property</code>元素的<code>ref</code>屬性進行引用,也可以在<code>property</code>元素下定義<code>bean</code>元素進行注入。對于其它集合類型,如<code>Set、List、Map、Array、Properties</code>等則可以在<code>property</code>元素下通過<code>set、list</code>等元素進行定義。

當我們需要通過構造方法或者<code>set</code>方法給<code>bean</code>注入一個普通的字元串類型的值時,我們可以直接進行注入,如下就是直接将字元串<code>“Value1”</code>通過<code>setP1()</code>方法注入對應的<code>bean</code>的示例。

當我們需要注入的普通字元串是<code>bean</code>容器中另一個<code>bean</code>的<code>beanName</code>時,我們還可以通過<code>idref</code>元素來指定對應的值,此時對應的值是通過<code>idref</code>元素的<code>bean</code>屬性來指定的。當使用<code>idref</code>元素來指定對應的值時<code>Spring</code>将檢查<code>ApplicationContext</code>中是否存在<code>id</code>或<code>name</code>為<code>idref</code>元素的<code>bean</code>屬性值的<code>bean</code>,是以當我們使用<code>idref</code>元素時需要我們的<code>ApplicationContext</code>中存在<code>idref</code>對應的<code>bean</code>。當我們需要指定的值确實是<code>ApplicationContext</code>中一個<code>bean</code>的<code>id</code>或<code>name</code>時,這可以幫助我們在<code>Spring</code>初始化對應的<code>bean</code>時就發現對應的錯誤。

在上述配置中我們給<code>id</code>為<code>hello</code>的<code>bean</code>通過<code>setP1()</code>方法注入的是字元串<code>world</code>,而不是其對應的<code>bean</code>。由于我們是通過<code>idref</code>元素來注入字元串<code>world</code>的,<code>Spring</code>将檢查<code>ApplicationContext</code>中是否存在<code>id</code>或<code>name</code>為<code>world</code>的<code>bean</code>。

不管是通過構造方法注入還是通過<code>set</code>方法注入依賴項,我們都可以通過<code>ref</code>元素關聯其它的<code>bean</code>。<code>ref</code>元素可以用來定義對應的關聯項,而真正的關聯項是通過<code>ref</code>元素的<code>bean</code>屬性或<code>parent</code>屬性來指定的,它們對應的是目标<code>bean</code>的<code>id</code>或<code>name</code>。

<code>ref</code>的<code>bean</code>屬性關聯和<code>parent</code>屬性關聯是不同的。通過<code>bean</code>屬性指定關聯時會在目前容器及其父容器中尋找關聯項,而通過<code>parent</code>屬性指定關聯時隻會在目前容器的父容器中尋找關聯項。

不管是通過構造方法注入還是通過<code>set</code>方法注入,我們都可以通過屬性<code>ref</code>來替代<code>&lt;ref bean=”…”/&gt;</code>,如上面的示例我們就可以替換成如下這樣:

設想一下我們的<code>beanA</code>有一個屬性<code>beanB</code>,而<code>beanB</code>又有一個屬性<code>beanC</code>,<code>beanC</code>又有一個屬性<code>propD</code>,我們可以直接在定義<code>beanA</code>的時候指定對應的<code>beanB</code>的屬性<code>beanC</code>的屬性<code>propD</code>的值,如:

其對應的語義是<code>beanA.getBeanB().getBeanC().setPropD(“ValueD”)</code>,是以能夠成功指定<code>propD</code>值的條件是<code>getBeanB()</code>不能為<code>null</code>,<code>getBeanB()</code>的<code>getBeanC()</code>也不能為<code>null</code>。當然,最終要注入的不一定是基本資料類型,換成是一個<code>bean</code>也是可以的,如:

(注:本文是基于Spring4.1.0所寫)