Bean属性的注入
上一文中的person类在spring容器中如何注入name属性的了?相信大家也猜得八九不离十了,是通过person这个类name属性的set方法注入的。当然还有其他方式可以注入,就是通过构造方法注入,前提是类中要有相应的构造方法。好的本章主要来讲Spring的构造器注入和setter方法注入。以及一些集合类型的注入。
构造器注入
在Spring XML配置中,只有一种声明bean的方式:使用<bean>
元素并指定class属性。Spring会从这里获取必要的信息来创建bean。但是,在XML中声明DI时,会有多种可选的配置方案和风格。具体到构造器注入,有两种基本的配置方案可供选择:
元素 - 使用Spring 3.0所引入的c-命名空间
两者的区别在很大程度就是是否冗长烦琐。可以看到,
编写Java的类,提供构造方法
public class Car {
private String name;
private double money;
public Car(String name, double money) {
this.name = name;
this.money = money;
}
@Override
public String toString() {
return "Car [name=" + name + ", money=" + money + "]";
}
}
编写配置文件
<bean id="car" class="com.itheima.demo4.Car">
<constructor-arg name="name" value="大奔"/>
<constructor-arg name="money" value="100"/>
</bean>
可以看出spring在初始化这个bean的时候是通过
相信大家看到这里已经了解了用
它是在XML中更为简洁地描述构造器参数的方式。要使用它的话,必须要在XML的顶部声
明其模式,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
...
</beans>
在c-命名空间和模式声明之后,我们就可以使用它来声明构造器参数了,如下所示:
<bean id="car" class="com.huya.demo.Car"
c:name="雅马哈" c:money="10000" />
当然上面的属性名字只是简单的写法。当构造器需要引入一个bean作为参数的时候属性名需要如下图这样定义:
属性名以“c:”开头,也就是命名空间的前缀。接下来就是要装配的构造器参数名,在此之后是“-ref”,这是一个命名的约定,它会告诉Spring,正在装配的是一个bean的引用,这个bean的名字是compactDisc,而不是字面量“compactDisc”。
setter方法注入
以上是我们用构造器来注入的简单列子,现在我们来看看怎么使用setter方法来注入。对比构造器的房子同样setter的注入在Spring XML配置文件中也有2中方式一个是<property>
元素还有一个是p-命名空间。很显然要使用这种方式一定要有set方法,接下来在上面的car类中添加属性的set方法。别忘了还要添加一个空参的构造方法,设置了有参的构造得话默认的空参构造就没了。
public void setName(String name) {
this.name = name;
}
public void setMoney(double money) {
this.money = money;
}
编写配置文件
<bean id="car" class="com.huya.demo.Car" >
<property name="name" value="奔驰"/>
<property name="money" value="3000" />
</bean>
可以看出value是以字面量的形式注入,当然property还有个ref属性。这就是和constructor-arg的ref作用一样的了。我们已经知道,Spring为
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
...
</beans>
我们可以使用p-命名空间,按照以下的方式装配Car的属性:
<bean id="car" class="com.huya.demo.Car"
p:name="奔驰" p:money="6666" />
p-命名空间中属性所遵循的命名约定与c-命名空间中的属性类似。下图阐述了p-命名空间属性是如何组成的。
首先,属性的名字使用了“p:”前缀,表明我们所设置的是一个属性。接下来就是要注入的属性名。最后,属性的名称以“-ref”结尾,这会提示Spring要进行装配的是引用,而不是字面量。要注入字面量的话去掉-ref就可以了。但需要注意的是,我们不能使用p-命名空间来装配集合,没有便利的方式使用p-命名空间来指定一个值(或bean引用)的列表。上面也说了c-命名空间不能完成但是<constructor-arg>
可以完成的一些事也是这样。接下来我们看看集合的注入。
集合的注入
如果用构造器的注入的话只能使用<constructor-arg>
相应的子元素如list、set、map和props等。我们再来改一下Car类如下,增加一个List集合属性表示轮子。
public class Car {
private String name;
private double money;
private List<String> wheel;
public Car(String name, double money,List<String> wheel) {
this.name = name;
this.money = money;
this.wheel = wheel;
}
@Override
public String toString() {
return "Car [name=" + name + ", money=" + money + ", wheel=" + wheel + "]";
}
}
配置文件:
<bean id="car" class="com.huya.demo.Car" >
<constructor-arg name="name" value="福特野马"/>
<constructor-arg name="money" value="88888" />
<constructor-arg name="wheel">
<list>
<value>前轮1</value>
<value>前轮2</value>
<value>后轮1</value>
<value>后轮2</value>
</list>
</constructor-arg>
</bean>
然后初始化这个bean并打印到控制台就是:
Car [name=福特野马, money=88888.0, wheel=[前轮1, 前轮2, 后轮1, 后轮2]]
其中,<list>
元素是<constructor-arg>
的子元素,这表明一个包含值的列表将会传递到构造器中。其中,<value>
元素用来指定列表中的每个元素。与之类似,我们也可以使用<ref>
元素替代<value>
,实现bean引用列表的装配。与之类似的如果用setter注入的话,<property>
元素也有集合所对应的的子元素这里我就不一一举例了。这里c-和p-命名空间不能注入集合属性的话那怎么办,当然了Spring提供了另一个Spring util-命名空间,它的作用就是把集合声明到Car这个bean的外面的单独的一个bean中,那么我们就可以使用-ref来指向它就可以了。同样使用Spring Util-命名空间也要在XML文件声明它的模式。以及改变一下bean的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="car" class="com.huya.demo.Car" >
<constructor-arg name="name" value="福特野马"/>
<constructor-arg name="money" value="88888" />
<constructor-arg name="wheel" ref="wheel"/>
</bean>
<util:list id='wheel'>
<value>前轮1</value>
<value>前轮2</value>
<value>后轮1</value>
<value>后轮2</value>
</util:list>
</beans>
有的人可能会说改怎么选择使用构造方法注入还是使用setter方法的属性注入了?作为一个通用的规则,我倾向于对强依赖使用构造器注入,而对可选性的依赖使用属性注入。至于使用标签还是命名空间这个就看个人爱好了,命名空间比较简洁容易看懂。好了本章就到这里了,读者可以思考一下,上面我所讲的都是硬编码形式注入的,有没有更加灵活注入了?