天天看点

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所写)