Spring-3注入Bean属性

Spring使用一种被称为是“依赖注入”的方式管理Bean之间的依赖关系。依赖注入是一种优秀的解耦方式。
Spring的依赖注入(Dependency Injection, DI)还有一个的名字:“控制反转”(Inversion of Control,IOC)。DI与IOC的含义完全相同。

注入Bean属性

依赖注入分为两种:构造器注入(通过构造参数来注入值)、设置注入(通过调用属性的setter方法来注入值)。

通常,JavaBean的属性是私有的,同时会提供一组存取器方法,以setXX()和getXXX()形式存在,spring的设置注入就是借助属性的set方法来配置属性的值。

注入简单值

1
2
3
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist">
<property name="song" value="Jingle Bells" />
</bean>

在Spring中我们使用元素配置Bean属性。类似,区别在于,前者是setter方法注入值,后者是通过构造参数注入值。

引用其他Bean

1
2
3
4
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist">
<property name="song" value="Jingle Bells" />
<property name="instrument" ref="saxophone" />
</bean>

==Spring只要看到子元素,Spring框架就会在底层以反射方式执行一次setter方法。==
Spring底层会执行形如一下格式的代码:

1
2
3
4
5
6
7
String nameStr = ...;
String refStr = ...;
String setterName = "set" + nameStr.substring(0, 1).toUpperCase() + nameStr.substring(1);// 生成将要调用的setter方法名
Object paramBean = container.get(setterName);
Method setter = class.getMethod(setterName, paramBean.getClass());
// 此处的Obj参数是前一段反射代码为<bean .../>元素创建的对象
setter.invoke(obj, paramBeam);

Spring底层代码会更完善一些。

注入内部Bean

内部bean是定义在其他bean内部的bean,如下配置将萨克斯声明为内部bean:

1
2
3
4
5
6
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist">
<property name="song" value="Jingle Bells" />
<property name="instrument">
<bean class="com.springinaction.springidol.Saxophone" />
</property>
</bean>

内部bean并不仅限于setter注入,我们还可以把内部bean装配到构造方法的入参中,正如下面的duke的新声明所展示的:

1
2
3
4
5
6
<bean id="duke" class="com.springinaction.springidol.PoeticJuggler">
<constructor-arg value="25" />
<constructor-arg>
<bean class="com.springinaction.springidol.Sonnet29" />
</constructor-arg>
</bean>

内部bean没有ID属性,虽然为内部bean配置一个ID属性完全是合法的,但是却没有必要。
内部类最大的缺点:不能被复用。内部bean仅适用于一次注入,而且也不能被其他bean应用。使用内部bean会影响Spring XML配置的可读性。

装配集合

value和ref仅在Bean的属性值是单个值的情况下才有用。当Bean的属性类型是集合时,又该如何配置呢?
String提供了4种类型的集合的装配元素:

集合元素 用途
装配list类型的值,允许重复
装配set类型的值,不允许重复
装配map类型的值,名称和值可以是任意类型
装配properties类型的值,名称和值必须是String类型

当属性为任意的Java.util.Collection类型时,几乎可以完全互换。

这两个元素分别对应java.util.Map和java.util.Properties。当我们需要由键-值对组成的集合时,这两种配置元素非常有用。

装配List、Set、Array

Hank能够同时演奏多种乐器,由类OneManBand定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.springinaction.springidol;

import java.util.Collection;

public class OneManBand implements Performer {
public OneManBand() {}

public void perform() throws PerformanceException {
for (Instrument instrument : instruments) {
instrument.play();
}
}

private Collection<Instrument> instruments; // 集合

public void setInstruments(Collection<Instrument> instruments) {
this.instruments = instruments;
}
}

我们使用list配置元素为Hank赋予表演时所用到的乐器集合:

1
2
3
4
5
6
7
8
9
<bean id="hank" class="com.springinaction.springidol.OneManBand">
<property name="instruments">
<list>
<ref bean="guitar" />
<ref bean="cymbal" />
<ref bean="harmonica" />
</list>
</property>
</bean>

list元素包含一个或多个值,这里的ref元素用来定义在spring上下文中的其他bean引用。当然还可以使用其他的spring设置元素作为list的成员,包括。实际上,list可以包含另一个list作为其成员,形成多维列表。

装配Map集合

当OneManBand表演时,假设我们还想知道每一个音符是由哪种乐器产生的,OneManBand可以调整如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.springinaction.springidol;

import java.util.Collection;
import java.util.Map;

public class OneManBand implements Performer {
public OneManBand() {}

public void perform() throws PerformanceException {
for (String key : instruments.keySet()) {
System.out.println(key + ":");
Instrument instrument = instruments.get(key);
instrument.play();
}
}

private Map<String, Instrument> instruments;

public void setInstruments(Map<String, Instrument> instruments) {
this.instruments = instruments;
}
}

使用map元素配置instruments属性,如下所示:

1
2
3
4
5
6
7
8
9
<bean id="hank" class="com.springinaction.springidol.OneManBand">
<property name="instruments">
<map>
<entry key="GUITAR" value-ref="guitar" />
<entry key="CYMBAL" value-ref="cymbal" />
<entry key="HARMONICA" value-ref="harmonica" />
</map>
</property>
</bean>

map中的entry元素由一个键和一个值组成,键和值可以是简单类型,也可以是其他类型的引用,这些属性将帮助我们指定entry的键和值:

属性 用途
key 指定map中entry的键为String
key-ref 指定map中entry的键为spring上下文中其他bean的引用
value 指定map中entry的值为String
value-ref 指定map中entry的值为spring上下文中其他bean的引用

装配Properties集合

1
2
3
4
5
6
7
8
9
<bean id="hank" class="com.springinaction.springidol.XXX">
<property name="instruments">
<props>
<prop key="GUITAR">STRUM STRUM STRUM</prop>
<prop key="CYMBAL">CRASH CRASH CRASH</prop>
<prop key="HARMONICA">HUM HUM HUM</prop>
</props>
</property>
</bean>

说明:

  1. 元素用于把值或bean引用注入到bean的属性中
  2. 元素用于定义一个java.util.Properties类型的集合值
  3. 元素用于定义集合的一个成员。

    装配空值

    通常情况下bean属性的最初值都是null,直到你为它赋值,但是有些bean会为它的属性默认设置一个非空值。如果因为某些特殊原因,必须把属性设置为空值,则可以显式地为该属性装配一个null值。
    为属性设置null值,只需使用元素,例如:
    1
    <property name="someNonNullProperty"><null/></property>

显式地为属性装配null值的另一个理由是覆盖自动装配的值。

使用命名空间p装配属性

跟命名空间p是等价的,命名空间p的最主要优点是更简洁。
命名空间p的schema URI为http://www.springframework.org/schema/p。如果你想使用命名空间p,主需要在spring的XML配置中增加如下一段声明:

1
2
3
4
5
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

使用范例如下:

1
2
3
<bean id="kenny2" class="com.springinaction.springidol.Instrumentalist"
p:song="Jingle Bells"
p:instrument-ref="saxophone" />

-ref后缀作为一个标识来告知spring应该装配一个引用而不是字面值。

分享到