Spring学习笔记(四) --- 装配Bean之通过XML装配
来源:互联网 发布:淘宝药品现在要怎么买 编辑:程序博客网 时间:2024/05/17 22:37
本系列博客为spring In Action 这本书的学习笔记
在之前的两篇博客里我们说完了自动装配和通过Java代码装配Bean, 这篇博文里我们将介绍最后一种装配Bean的方式 — 通过XML装配.
1. 创建一个XML配置文件
和上一篇通过Java装配Bean的博文里面一样, 我们先来看一下在自动装配中出现过的XML文件.
程序1: 在CD播放器里面出现过的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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="com.SoundSystem_Auto" /></beans>
这个程序1与上一篇通过Java代码装配Bean的博客里面的那个程序1都取自Spring学习笔记(二): 装配Bean之自动化装配那篇博客里. 其意义都是通过显式配置启用组件扫描.
<context:component-scan base-package=”com.SoundSystem_Auto” />这句代码等同于JavaConfig里面的@ComponentScan, 意为在Spring中启用组件扫描.
这是在前面出现过的XML配置文件, 那么我们现在来看一下一个普通的, 没有进行任何配置的XML配置文件是什么样的.
程序2: 创建一个普通的规范的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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--Configuration details go here--> <!--在这里写配置的细节--></beans>
这就是一个最简单的XML配置文件, 我们可以看出, 它跟同样功能的JavaConfig相比, 复杂了很多. 在JavaConfig中只需要一个@Congfiguration标注就可以声明一个Java配置文件, 但是在XML配置文件中, 需要在顶部声明多个XML模式(即XSD文件), 这些文件定义了配置Spring的XML元素.
用来装配Bean的最基本的XML元素包含在spring-beans模式之中, 在上面这个XML文件中, 它被命名为根空间. <beans>是该模式中的一个元素, 它是所有Spring配置的根元素.
2. 声明一个简单的Bean
上面介绍了怎样创建一个规范的XML配置文件, 那么现在就来看看怎样在XML配置文件中声明Bean.
要在XML中声明一个Bean, 要用到spring-beans模式中的另一个元素<bean>. <bean>元素类似于JavaConfig中的@Bean注解.
现在我们想要声明一个CompactDisc Bean, 我们可以在XML文件的<beans>标签下这样写:
程序3: 在XML中通过<bean>声明一个Bean
<bean class = "com.SoundSystem_XML.Jay" />
这样就声明了一个简单的Bean, 创佳那这个Bean是通过class属性的全限定类名来指定的. 在这个Bean中, 并没有给出明确的Bean的ID, 所以Spring将会根据全限定的类名来给这个Bean命名, 比如这个Bean的ID为:”com.SoundSystem_XML#0”. 如果使用这个全限定类名再声明一个Bean, 那么, 它的ID将为:”com.SoundSystem_XML#1”.
但是这样虽然在创建Bean的时候很方便, 但是在使用这个Bean的时候又会回很麻烦, 所以一般情况下, 我们将采用给Bean自定义ID, 比如下面这样:
程序4: 给Bean自定义ID
<bean id="jay" class = "com.SoundSystem_XML.Jay" />
这样在稍后将这个Bean装配到CDPlayer Bean中的时候, 我们就可以直接使用这个具体的名字.
现在已经知道了如何在XML配置文件中声明一个Bean, 那么, 相比于JavaConfig, Spring到底是如何通过XML配置文件来创建一个Bean的.
在JavaConfig中, 我们需要编写带有@Beam标注的方法, 这些方法回返回一个new的对象, 然后Spring将这个对象包装成Bean.
在XML中, 我们使用全限定的类名来为Spring创建Bean指定路径. 也就是说, Spring会根据这个全限定的类名找到这个类, 并调用该类的默认构造器来创建Bean.
看起来XML好像更省事一些, 但是它并没有JavaConfig那么强大, JavaConfig可以使用任何你能用Java代码实现的方式来创建一个Bean.
而且, 通过XML的全限定类名来创建Bean, 如果突然改变了类名, 那又将造成很多麻烦.
3. 注入(装配)Bean
我们可以回想一下, 在JavaConfig中有两种注入Bean方式, 那么在XML配置文件中也有两种注入Bean的方式. 分别是通过构造器注入Bean和通过setter设置属性所注入Bean.
(1) 通过构造器注入Bean
什么叫通过构造器注入Bean呢? 前面讲过了, 在XML中声明Bean时, 使用全限定的类名来指定一个类, 然后Spring调用这个类的默认构造方法new出一个对象, 然后将其包裹成Bean.
那么, 如果这个类我们给其自定义了构造方法, 我们就可以在XML中对其进行注入, 完成Bean的初始化工作. 可能你还有些不明白, 先看一个例子吧.
仍然是CD播放器的例子, 先给出一个CD播放器的类.
程序5: CD播放器的类
public class CDPlayer implements MediaPlayer { private CompactDisc cd; @Autowired public CDPlayer(CompactDisc cd){ this.cd = cd; } public void play() { cd.play(); }}
可以看到, 在CDPlayer类的构造方法需要一个CompactDisc对象, 如果我们要初始化这个Bean, 就要完成CompactDisc Bean的注入.
在XML中, 通过构造器注入Bean有两种配置方式
- <constructor-arg>元素
- 使用Spring的c-命名空间
我们先来看一下<constructor-arg>元素配置方式
1. <constructor-arg>元素配置方式
程序6: <constructor-arg>元素配置方式注入初始化CDPlayer Bean
<bean id="cdPlayer" class="com.SoundSystem_XML.CDPlayer"> <constructor-arg ref="jay" /></bean>
<constructor-arg>元素会告知Spring要将一个ID为jay的Bean引用传递到CDPlayer的构造器中.
同样的, 还有c-命名空间配置注入Bean
2. c-命名空间配置方式
程序7: c-命名配置方式注入Bean
<bean id="cdPlayer1" class="com.SoundSystem_XML.CDPlayer" c:cd-ref="jay" />
c-命名空间这种[配置方式看起来有点怪异, 我们来分析一下c:cd-ref=”jay”这句代码里面的各个参数.
- c:是c-命名空间的前缀;
- cd是构造器的参数名, 也就是CDPlyer构造方法的参数列表里面的参数名;
- -ref是注入Bean引用; “jay”是要注入的Bean的ID.
关于c-命名空间, 还有一些别的使用规则. 比如, 当构造器中需要多个Bean的时候, 我们可以使用参数索引来表示参数列表里所需要的多个Bean. 比如这样:
<bean id="cdPlayer2" class="com.SoundSystem_XML.CDPlayer" c:_0-ref="jay"/>
(2) 通过构造器注入常量
上面介绍的是通过构造器注入Bean, 但是有的时候, 构造器的参数并不是一个类变量, 而是一个常量. 那么就来看一下如何通过构造器注入常量.
假设现在有一个周杰伦的CD如下:
程序8: JayZhou CD
public class JayZhou implements CompactDisc { private String title; private String artist; public JayZhou(String title, String artist){ this.title = title; this.artist = artist; } public void play() { System.out.println("Playing " + title + " by " + artist); }}
就这个类的构造器而言, 它的两个参数都是常量, 所以要通过XML将常量注入. 和前面一样, 将常量注入到构造器中, 也有两种方式:
- <constructor-arg>元素
- 使用Spring的c-命名空间
1. <constructor-arg>元素配置方式
程序9: 将常量注入到构造器中
<bean id="jayZhou1" class="com.SoundSystem_XML.JayZhou" > <constructor-arg value="魔杰座" /> <constructor-arg value="周杰伦" /></bean>
每种注入方式都是有多种书写格式的, 比如还可以像下面这样:
<bean id="jayZhou" class="com.SoundSystem_XML.JayZhou" > <constructor-arg index="0" value="魔杰座"/> <constructor-arg index="1" value="周杰伦"/></bean>
究竟使用哪种, 全凭个人喜好.
2. c-命名空间配置方式
用c-命名空间配置方式可以像下面这样注入:
程序10: 使用c-命名空间注入
<bean id="jayZhou2" class="com.SoundSystem_XML.JayZhou" c:title="魔杰座" c:artist="周杰伦" />
这种注入方式是通过构造器的参数列表的参数名称来指定, 也可以像前面注入Bean那样, 使用索引来指定要注入的常量. 比如下面这样:
<bean id="jayZhou3" class="com.SoundSystem_XML.JayZhou" c:_0="魔杰座" c:_1="周杰伦" />
3. 装配Bean时注入列表/集合/数组
需要特别说明的是, 在装配Bean的时候, 如果我们要注入的是一个数组/列表/集合呢? 那么我们就需要用到<list>元素.
假设现在有一个五月天的新专辑类, 我们要对这个CD进行一些更细致的处理, 比如显示出播放这个CD里面的每一首歌:
程序11: 五月天的新专辑
public class MayDayDisc implements CompactDisc { private String title; private String artist; private List<String> tracks;// private Set<String> tracks;// 一般来说, List和Set的区别不是很大, 但是当Spring要装配的是集合的时候, 使用Set集合可以保证集合中的元素不会重复. public MayDayDisc(String title, String artist, List<String> tracks){ this.title = title; this.artist = artist; this.tracks = tracks; } public void play() { System.out.println("Playing " + title + " by " + artist); for(String track : tracks){ System.out.println("-Track: " + track); } }}
那么这个时候, XML文件里应该这样配置:
<bean id="mayDay1" class="com.SoundSystem_XML.MayDayDisc"> <constructor-arg value="五月天的新专辑" /> <constructor-arg value="五月天" /> <constructor-arg> <list> <value>歌曲1</value> <value>歌曲2</value> <value>歌曲3</value> <!--等等...--> </list> </constructor-arg> </bean>
在上面的代码中提到过, 在类里除了使用List, 也可以使用Set, 不过就是将相对应的XML配置文件中的<list>元素改为<set>就可以了.
同理, 如果现在有一个电台, 要播放若干CD. 我们也可以将若干CD类使用<list>元素, 注入到电台类中.
程序12: 电台
public class Discography { private String artist; private List<CompactDisc> cds; public Discography(String artist, List<CompactDisc> cds){ this.artist = artist; this.cds = cds; }}
而其相对应的XML应该是这样:
<bean id="discpgraphy" class="com.SoundSystem_XML.Discography"> <constructor-arg index="0" value="今日流行"/> <constructor-arg index="1"> <list> <ref bean="jay" /> <ref bean="jayZhou" /> <ref bean="mayDay" /> </list> </constructor-arg> </bean>
以上就是关于通过构造器装配(注入)Bean的内容就说到这里, 下面我们来看一下怎样通过设置属性来装配(注入)Bean.
(3) 通过设置属性注入Bean
在Java中, 除了通过构造方法给数据成员赋值以外, 我们还可以通过setter方法给数据成员赋值.
与通过构造器注入Bean一样, 通过设置属性注入Bean也有两种装配方式:
- 通过<property>元素装配
- 通过p-命名空间装配
1. 通过<property>元素装配
我们现在对CDPlyer类进行修改, 去掉它的自定义构造方法, 加上所有数据成员的setter方法:
程序13: CDPLyer
public class CDPlayer implements MediaPlayer { private CompactDisc cd; @Autowired public void setCd(CompactDisc cd){ this.cd = cd; } public void play() { cd.play(); }}
如果现在要在XML中重新声明这个类, 我们可能会这样声明:
<bean id="cdPlayer" class = "com.SoundSystem_XML.CDPlayer" />
这样看起来是没有问题的, 毕竟现在这个类没有自定义的构造方法了嘛, 默认的构造方法也是不含参数的. 可是这样真的对吗? 如果我们测试这个类, 会发现它会抛出NullPoiterException异常, 因为我们没有注入任何CompactDisc Bean, 所以运行play()方法当然就出错了.
要通过设置属性注入Bean, 这时候我们就要用到<property>元素了. <property>元素为设置属性的setter方法所提供的功能和<constructor-arg>元素为构造器提供的功能是一样的. 比如现在可以在XML中这样写:
<bean id="cdPlayer3" class="com.SoundSystem_XML.CDPlayer"> <!--这里的property的name属性要与setXXX()方法里面的XXX保持一致(XXX首字母应该小写)--> <property name="cd" ref="jay"/></bean>
2. 通过p-命名空间装配
程序14: 通过p-命名空间来装配Bean
<bean id="cdPlayer4" class="com.SoundSystem_XML.CDPlayer" p:cd-ref="jay"></bean>
同样的, p-命名空间的参数也比较难理解, 现在我们也来分析一下p:cd-ref=”jay”里的各项参数:
- p:是p-命名空间的前缀;
- cd是属性名(即类中的数据成员名);
- -ref是注入Bean引用, 告知Spring这是注入一个Bean而不是常量;
- “jay”是所注入的Bean的ID
(4) 通过设置属性注入常量
有了前面通过构造器注入常量的例子, 这里的通过设置属性注入常量应该也不难理解.
与前面一样, 通过设置属性注入常量也有两种装配方式:
- 通过<property>元素装配
- 通过p-命名空间装配
1. 通过<property>元素装配
我们先对五月天的新专辑类进行一些修改, 去掉它的构造方法, 加上所有数据成员的setter方法.
程序15: 五月天的新专辑类
public class MayDayDisc implements CompactDisc { private String title; private String artist; private List<String> tracks; public void setTitle(String title){ this.title = title; } public void setArtist(String artist){ this.artist = artist; } public void setTracks(List<String> tracks){ this.tracks = tracks; } public void play() { System.out.println("Playing " + title + " by " + artist); for(String track : tracks){ System.out.println("-Track: " + track); } }}
在XML中应该这样配置:
<bean id="mayDay3" class="com.SoundSystem_XML.MayDayDisc"> <property name="title" value="五月天的新专辑" /> <property name="artist" value="五月天" /> <property name="tracks"> <list> <value>歌曲1</value> <value>歌曲2</value> <value>歌曲3</value> <value>歌曲4</value> <!--等等...--> </list> </property> </bean>
2. 通过p-命名空间装配
使用p-命名空间装配的时候还有一丢丢小麻烦, 不过我们先把装配的代码贴出来, 再对它进行解释:
<bean id="mayDay4" class="com.SoundSystem_XML.MayDayDisc" p:title="五月天的新专辑" p:artist="五月天"> <property name="tracks"> <list> <value>歌曲1</value> <value>歌曲2</value> <value>歌曲3</value> <value>歌曲4</value> <!--等等...--> </list> </property> </bean>
可以看出, 再注入列表常量的时候, 没有使用p-命名空间, 而是使用了<property>元素. 事实上, p-命名空间是不能装配集合的.
但是, 我们仍然有简化书写的办法, 就是使用util-命名空间.
我们可以使用util-命名空间的<util:list>元素来创建一个Bean, 然后再通过p-命名空间的ref来引用这个Bean. 具体代码如下:
<util:list id="trackList"> <value>歌曲1</value> <value>歌曲2</value> <value>歌曲3</value> <value>歌曲4</value> <!--等等...--> </util:list> <bean id="mayDay5" class="com.SoundSystem_XML.MayDayDisc" p:title="五月天的新专辑" p:artist="五月天" p:tracks-ref="trackList"> </bean>
<util:list>元素只是util-命名空间所提供的功能之一, 它还有许多其它的元素, 比如:
- <util:constant> : 引用某个类型的public static域, 并将其暴露为Bean;
- <util:list> : 创建一个java.util.List类型的Bean, 其中包含值或引用;
- <util:map> : 创建一个java.util.Map类型的Bean, 其中包含值或引用;
- <util:properties> : 创建一个java.util.Properties类型的Bean;
- <util:property-path> : 引用一个Bean的属性(或内嵌属性), 并将其暴露为Bean;
- <util:set> : 创建一个java.util.Set类型的Bean, 其中包含值或引用.
- Spring学习笔记(四) --- 装配Bean之通过XML装配
- Spring之通过XML装配bean(三)
- Spring学习笔记(三) --- 装配Bean之通过Java代码装配Bean
- 【Spring学习笔记四】-自动装配Bean
- Spring学习笔记之通过Java代码装配Bean
- Spring学习笔记之通过XML装配Bean的一些细节
- Spring学习笔记(二) --- 装配Bean之自动化装配
- Spring学习笔记(六) --- 装配Bean之高级装配
- Spring笔记 - Bean xml装配
- Spring学习笔记之Bean装配
- Spring学习笔记之Bean的装配
- Spring学习笔记之自动化装配Bean
- 2.Spring学习笔记之装配Bean
- Spring装配Bean——通过配置XML装配bean
- spring笔记:第二章(通过xml装配bean)
- Spring 如何通过 XML 装配 bean?
- 一步一步学Spring-通过xml装配bean
- Spring学习笔记(9.Spring Bean装配之Resource)
- batch normalization 中的 beta 和 gamma参数
- 欧几里得算法&&扩展欧几里得算法
- 对知识图谱的理解报告
- 洛谷 P1799 数列_NOI导刊2010提高(06)
- ESL作业笔记2.5:最小二乘法预测输出的误差期望
- Spring学习笔记(四) --- 装配Bean之通过XML装配
- Ubuntu16.04上启动Spyder出现错误AttributeError: 'module' object has no attribute '_base'
- 实验一线性表的基本操作实现及其应用
- 阿里云ubuntu16.04实测配置【php+mysql+apache】
- Fragment面试总结
- HTTP响应状态码及其含义
- 连续子段和问题(动态规划)
- Android TextView 通过代码设置加粗和取消加粗 等效果无反应或者反应缓慢
- jQuery绑定事件及动画效果