在前两篇中分别介绍了自动化装配机制和通过JavaConfig类进行装配,接下来介绍下通过XML装配bean,其实就目前趋势来看,这种方式用的越来越少(不是我说的,是作者说的,喜欢这种方式的别喷我??)。。。。但是呢,由于历史遗留问题,我们不得不会这种方式,否则公司前辈们的代码,可能就看不懂了,所以看过来
3. 通过XML装配bean
1)创建XML配置规范
使用XML为Spring装配bean之前,需要创建一个新的配置规范,在使用JavaConfig的时候,意味着要创建一个带有@Configuration注解的类,而在XML配置中,意味着创建一个这么XML文件,并且要以<beans>元素为根,如下(允许我截书上的偷个懒):
那这个就很明显了,同等功能,XML配置方法比JavaConfig类复杂的多。至于上面这个文件的根元素<beans>中包含的那些信息,我就不细讲了,只要知道这里指定了一些XML约束来规范当前XML文件就行了,这里用的XSD技术,另一种常见的XML约束是DTD技术,有兴趣的可自行度娘了。。。
2)声明一个bean
声明一个bean,需要用到的就是<bean>标签,他就类似于JavaConfig中的@Bean注解,使用方式如下:
<bean class = "com.fion.Car" />
需要注意的是,在指定bean的所属类时,一定要用全限定的类名。那么问题来了,这个bean的ID是什么呢?就这个例子而言,这个bean的ID将会是“com.fion.Car#0”,其中,"com.fion.Car"当然就是class的值,而“#0”是一个计数的形式,如果再有一个class为“com.fion.Car”的bean,并且没有为其指定ID的,那么它的ID将为“com.fion.Car#1”。一般使用时,上面这种不指定而是由自动化分配ID的方式当然是不被推荐的,一般的写法如下:
<bean id = "car" class = "com.fion.Car" />
这样,这个bean的ID就会被指定为id的值,也就是“car”。。。。
3)注入
常用的注入方式呢有两种,一种是构造器注入,另一种是Setter方法注入。
a)构造器注入
构造器注入一般使用到<constructor-arg>元素,使用方法如下:
<bean id = "car" class = "com.fion.Car" > <constructor-arg ref = "wheels"> </bean>
这样当Spring遇到这个<bean>元素时,就会创建一个Car的实例,并且为其注入wheels(假设Spring容器中已经存在)。个人认为呢,这种方式已经挺简洁的了,但是大神们不满足啊,所以还有一种方式叫c-命名空间,也可以实现构造器注入,所以我是个没有追求的人??。。。。。使用方式如下了:
<bean id = "car" class = "com.fion.Car" c:wheels-ref = "wheels" />
上面这段也可起到同样的作用,但是在使用c-命名空间之前需要在XML文件顶部声明其模式才可哦,自行度娘吧,先来了解一下c-命名空间的结构说明,上面这段配置就自然知道了,如下:
上面这段配置有用到构造器的参数名,这样看起来很怪,所以c-命名空间还提供一种方法,就是通过索引注入,如下:
<!-- 假设Car的构造器为Car(Wheels wheels) --> <bean id = "car" class = "com.fion.Car" c:_0-ref = "wheels" /> <!-- 上面这种只有一个参数,0也可省略 --> <bean id = "car" class = "com.fion.Car" c:_-ref = "wheels" /> <!-- 假设Car的构造器为Car(Wheels wheels, Brand brand) --> <bean id = "car" class = "com.fion.Car" c:_0-ref = "wheels" c:_1-ref = "brand"/>
通过上面这段配置中的注释,几乎都能看懂和了解,但是有点疑问,为什么数字前需要一个下划线“_”?那是因为XML中不允许数字作为属性的第一个字符,因此必须要添加一个下划线作为前缀。
那到目前为止,所说的注入都是注入引用,也就是注入bean,那如果只是注入个值怎么办呢?其实很简单,就是将<constructor-arg ref = "xxxBean">改成<constructor-arg value = "xxxConst">,将"c:xxxParam-ref"改成"c:_xxxParam",将"c:_0-ref"改成"c:_0",此处就不举例了,可自行动手试试。
这么看来c-命名空间还是很简单的,但是有一点他做不到,就是集合注入,现在如果构造器参数是一个集合,那么他就束手无策了,此时就需要<constructor-arg>标签出手了,我们来看下面这样的一个例子:
<!-- 假设Car构造函数是Car(List<Seat> seats),那么下面这种方式就会为其注入5张椅子了 --> <bean id = "car" class = "com.fion.Car" > <constructor-arg> <list> <ref bean = "seat1"> <ref bean = "seat2"> <ref bean = "seat3"> <ref bean = "seat4"> <ref bean = "seat5"> </list> </constructor-arg> </bean>
上面这种是bean列表的装配,若是值列表装配的话,只需用value替换ref即可。其他一些集合,如Set等注入方式与List类似,有兴趣可自行度娘。
b)Setter方法注入
Setter方法一般用到一个<property>标签,方法如下:
<bean id = "car" class = "com.fion.Car" > <property name = "wheels" ref = "wheels"> </bean>
事实上也很简单啦,<property>元素为属性的Setter方法所提供的功能与<constructor-arg>元素为构造器提供的功能是一样的。那可能有人就会想了,既然<constructor-arg>对应的有c-命名空间,那<property>有吗?别说,还真有,那就是p-命名空间,使用方法如下:
<bean id = "car" class = "com.fion.Car" p:wheels-ref = "wheels" >
是不是越看越像c-命名空间,别急,当你看到p-命名空间是如何组成的,你会发现更像,如下:
这样的话,对应于构造器注入,可以联想一下字面量注入和集合注入,<property>和p-命名空间分别该怎么处理。
好了,今天就到这了,后面的笔记可能会写的越来越没那么细,时间有限,工作繁忙,只能先这样了,??。。。。。。