丰富Bean的配置
关于Bean是如何配置的,大家并不陌生。毕竟前文曾有涉及,虽然比较粗浅。却也介绍了如何写份XML配置文件,告诉Spring容器怎样创建Bean,怎样注入依赖,等等。其中要点如下:
1.
2.
因此,假如com.dream包现有这样一些类:
1 public class Music { 2 private String musicName = null; 3 4 public String getMusicName() { 5 return this.musicName; 6 } 7 8 public void setMusicName(String musicName) { 9 this.musicName = musicName; 10 } 11 }
1 public class Player { 2 private Music playingMusic = null; 3 4 public Music getPlayingMusic() { 5 return this.playingMusic; 6 } 7 8 public void setPlayingMusic(Music playingMusic) { 9 this.playingMusic = playingMusic; 10 } 11 }
则可这样配置Bean:
1 <beans /* 省略命名空间和XSD模式文件声明 */> 2 <bean id="music" class="com.dream.Music"> 3 <property name="musicName" value="执着"/> 4 bean> 5 <bean id="player" class="com.dream.Player"> 6 <property name="playingMusic" ref="music"/> 7 bean> 8 beans>
这段配置能够告诉Spring容器创建music,player这两个Bean之后,通过属性注入Bean所需的依赖。也就是通过
1 <beans xmlns:p="http://www.springframework.org/schema/p" 2 /* 省略命名空间和XSD模式文件声明 */> 3 <bean id="music" class="com.dream.Music" p:musicName="执着"/> 4 <bean id="player" class="com.dream.Player" p:playingMusic-ref="music"/> 5 beans>
新的配置引入p-命名空间 xmlns:p="http://www.springframework.org/schema/p" 之后,做了两处改动:
1.使用 p:musicName="执着" 代替
2.使用 p:playingMusic-ref="music" 代替
这是怎么回事呢?
原来,p-命名空间可以代替
因此,修改之后的配置使用p-命名空间 p:musicName="执着" 代替
于是我们知道了,p-命名空间能以一种简洁紧凑的方式代替
构造函数注入
很多时候,我们希望一步到位,通过构造函数完成Bean的创建与装配。为了满足这样的需求,Spring提供了些支持,让我们能向XML配置文件提供一些信息,告诉Spring容器创建Bean的时候不是调用默认构造函数,而是调用其它具有某些参数的构造函数;从而能在创建Bean的同时通过构造函数注入Bean所需的依赖,完成Bean的创建与装配。
因此,假如com.dream包现有这样一些类:
1 public class Music { 2 private String musicName = null; 3 4 public Music(String musicName) { 5 this.musicName = musicName; 6 } 7 }
1 public class Player { 2 private Music playingMusic = null; 3 4 public Player(Music playingMusic) { 5 this.playingMusic = playingMusic; 6 } 7 }
则可这样配置Bean:
1 <beans /* 省略命名空间和XSD模式文件声明 */> 2 <bean id="music" class="com.dream.Music"> 3 <constructor-arg type="java.lang.String" value="执着"/> 4 bean> 5 <bean id="player" class="com.dream.Player"> 6 <constructor-arg type="com.dream.Music" ref="music"/> 7 bean> 8 beans>
可以看到构造函数注入是用
就该示例而言,Spring容器读取配置信息之后,发现music这个Bean的创建需要调用的构造函数具有一个String类型的参数。于是,Spring容器根据配置文件提供的信息把字符串“执着”传给符合条件的构造函数,并在调用之后完成Bean的创建与装配;发现player这个Bean的创建需要调用的构造函数具有一个Music类型的参数。于是,Spring容器根据配置文件提供的信息把music这个Bean传给符合条件的构造函数,并在调用之后完成Bean的创建与装配。
讲到这里,兴许大家开始困惑了:“如果配置的构造函数具有多个相同类型的参数,Spring容器调用构造函数的时候,怎么知道该把哪个值传给哪个参数,完成Bean的创建与装配呢?”
关于这个问题,我们可以引入
另外,除了参数索引,我们也能使用
还有,同p-命名空间能够代替
1 <beans xmlns:c="http://www.springframework.org/schema/c" 2 /* 省略命名空间和XSD模式文件声明 */> 3 <bean id="music" class="com.dream.Music" c:musicName="执着"/> 4 <bean id="player" class="com.dream.Player" c:playingMusic-ref="music"/> 5 beans>
新的配置引入c-命名空间 xmlns:c="http://www.springframework.org/schema/c" 之后,做了两处改动:
1.使用 c:musicName="执着" 代替
2.使用 c:playingMusic-ref="music" 代替
这是怎么回事呢?
原来,c-命名空间可以代替
因此,修改之后的配置使用c-命名空间 c:musicName="执着" 代替
读到这里,兴许大家已经察觉:“c-命名空间用到了参数名,而Spring容器获取参数名需要调试标志。如果编译代码的时候没有启用调试标志,这种配置方式岂不是有问题?”
是的,确实如此。因此,c-命名空间也支持参数索引。如下所示:
1 <beans xmlns:c="http://www.springframework.org/schema/c" 2 /* 省略命名空间和XSD模式文件声明 */> 3 <bean id="music" class="com.dream.Music" c:_0="执着"/> 4 <bean id="player" class="com.dream.Player" c:_0-ref="music"/> 5 beans>
引入参数索引之后,原来的 c:musicName="执着" 变成 c:_0="执着" ,原来的 c:playingMusic-ref="music" 变成 c:_0-ref="music" 。也就是说,原来的参数名变成下划线+索引。其中,索引前面的下划线是必须的,因为XML不允许属性名以数字作为开头。引入参数索引之后,Spring容器创建Bean的时候,会按参数索引指定的顺序依次把相应的参数值传给构造函数,并在调用之后完成Bean的创建与装配。
于是我们知道了,Spring容器既能通过属性注入依赖,也能通过构造函数注入依赖。至于该用属性注入还是构建函数注入,则是个人偏好问题。一般而言,强依赖(也就是只有完成注入,程序才能正常运行的依赖)通常选用构造函数注入,可选依赖(也就是不管注入有没有完成,程序都能正常运行的依赖)通常选用属性注入。
静态工厂方法注入
总有那么一些时候,我们的类存在一些专门用于创建对象的静态方法,俗称静态工厂方法。如果我们希望通过静态工厂方法创建Bean,只需向配置文件提供一些信息,告诉Spring容器调用静态工厂方法完成Bean的创建与装配即可。
因此,假如com.dream包现有这样一些类:
1 public class Music { 2 private String musicName = null; 3 4 public Music(String musicName) { 5 this.musicName = musicName; 6 } 7 8 public static Music staticFactory(String musicName) { 9 return new Music(musicName); 10 } 11 }
1 public class Player { 2 private Music playingMusic = null; 3 4 public Player(Music playingMusic) { 5 this.playingMusic = playingMusic; 6 } 7 8 public static Player staticFactory(Music playingMusic) { 9 return new Player(playingMusic); 10 } 11 }
则可这样配置Bean:
1 <beans /* 省略命名空间和XSD模式文件声明 */> 2 <bean id="music" class="com.dream.Music" factory-method="staticFactory"> 3 <constructor-arg type="java.lang.String" value="执着"/> 4 bean> 5 <bean id="player" class="com.dream.Player" factory-method="staticFactory"> 6 <constructor-arg type="com.dream.Music" ref="music"/> 7 bean> 8 beans>
可以看到
因此,这段配置用于告诉Spring容器:music这个Bean需要调用com.dream.Music类的staticFactory静态工厂方法进行创建,而且调用的时候需要注入“执着”这个字面量值;player这个Bean需要调用com.dream.Player类的staticFactory静态工厂方法进行创建,而且调用的时候需要注入music这个Bean引用。
实例工厂方法注入
工厂方法除了静态工厂方法,还有实例工厂方法。如果我们希望通过实例工厂方法创建Bean,只需向配置文件提供一些信息,告诉Spring容器调用某个Bean的实例工厂方法完成Bean的创建与装配即可。
因此,假如com.dream包现有这样一些类:
1 public class Music { 2 private String musicName = null; 3 4 public Music() { 5 } 6 7 public Music(String musicName) { 8 this.musicName = musicName; 9 } 10 11 public Music instanceFactory(String musicName) { 12 return new Music(musicName); 13 } 14 }
1 public class Player { 2 private Music playingMusic = null; 3 4 public Player() { 5 } 6 7 public Player(Music playingMusic) { 8 this.playingMusic = playingMusic; 9 } 10 11 public Player instanceFactory(Music playingMusic) { 12 return new Player(playingMusic); 13 } 14 }
则可这样配置Bean:
1 <beans /* 省略命名空间和XSD模式文件声明 */> 2 <bean id="music_1" class="com.dream.Music"/> 3 <bean id="music_2" factory-bean="music_1" factory-method="instanceFactory"> 4 <constructor-arg type="java.lang.String" value="执着"/> 5 bean> 6 7 <bean id="player_1" class="com.dream.Player"/> 8 <bean id="player_2" factory-bean="player_1" factory-method="instanceFactory"> 9 <constructor-arg type="com.dream.Music" ref="music_2"/> 10 bean> 11 beans>
这里配置了四个Bean:music_1,music_2,player_1,player_2。其中,music_2,player_2就是通过实例工厂方法创建的。
配置实例工厂方法时,需用factory-method属性指定实例工厂方法,factory-bean属性指定实例工厂方法所属的Bean,
因此,这段配置用于告诉Spring容器:music_2这个Bean需要调用music_1这个Bean的instanceFactory实例工厂方法进行创建,而且调用的时候需要注入“执着”这个字面量值;player_2这个Bean需要调用player_1这个Bean的instanceFactory实例工厂方法进行创建,而且调用的时候需要注入music_2这个Bean引用。
NULL值注入
NULL值的注入可用
1 <bean id="player_1" class="com.dream.Player"> 2 <constructor-arg type="com.dream.Music"> 3 <null /> 4 constructor-arg> 5 bean>
1 <bean id="player_2" class="com.dream.Player"> 2 <property name="playingMusic"> 3 <null /> 4 property> 5 bean>
集合注入
Java提供了多种类型的集合,常见的有List,Set,Map,等等。自然而然的,Spring提供了些支持,用于配置集合的注入。
因此,假如com.dream包现有这样一些类:
1 public class Music { 2 private ListmusicNameList = null; 3 4 public List getMusicNameList() { 5 return this.musicNameList; 6 } 7 8 public void setMusicNameList(List musicNameList) { 9 this.musicNameList = musicNameList; 10 } 11 }
1 public class Player { 2 private ListplayingMusicList = null; 3 4 public List getPlayingMusicList() { 5 return this.playingMusicList; 6 } 7 8 public void setPlayingMusicList(List playingMusicList) { 9 this.playingMusicList = playingMusicList; 10 } 11 }
则可这样配置Bean:
1 <beans /* 省略命名空间和XSD模式文件声明 */> 2 <bean id="music_1" class="com.dream.Music"/> 3 <bean id="music_2" class="com.dream.Music"> 4 <property name="musicNameList"> 5 <list> 6 <value>执着value> 7 <value>一生有你value> 8 list> 9 property> 10 bean> 11 <bean id="player" class="com.dream.Player"> 12 <property name="playingMusicList"> 13 <list> 14 <ref bean="music_1"/> 15 <ref bean="music_2"/> 16 list> 17 property> 18 bean> 19 beans>
可以看到List类型的集合能用元素配置。底下有个
当然有的。要知道p-命名空间,c-命名空间是不支持集合的。因此,Spring在spring-util.xsd模式文件里定义了些XML元素,用于描述诸如集合之类的创建信息。而这,需要引入spring-util.xsd模式文件之后修改如下:
1 <beans /* 省略命名空间和XSD模式文件声明 */ 2 xmlns:util="http://www.springframework.org/schema/util" 3 xsi:schemaLocation=" 4 /* 省略命名空间和XSD模式文件声明 */ 5 http://www.springframework.org/schema/util 6 http://www.springframework.org/schema/util/spring-util.xsd"> 7 8 <bean id="music_1" class="com.dream.Music" /> 9 <bean id="music_2" class="com.dream.Music"> 10 <property name="musicNameList" ref="utilMusicNameList"/> 11 bean> 12 <bean id="player" class="com.dream.Player"> 13 <property name="playingMusicList" ref="utilPlayingMusicList" /> 14 bean> 15 16 <util:list id="utilMusicNameList"> 17 <value>执着value> 18 <value>一生有你value> 19 util:list> 20 <util:list id="utilPlayingMusicList"> 21 <ref bean="music_1" /> 22 <ref bean="music_2" /> 23 util:list> 24 25 beans>
可以看到spring-util.xsd模式文件定义了
假如com.dream包现有这样一些类:
1 public class Music { 2 private SetmusicNameSet = null; 3 4 public Set getMusicNameSet() { 5 return this.musicNameSet; 6 } 7 8 public void setMusicNameSet(Set musicNameSet) { 9 this.musicNameSet = musicNameSet; 10 } 11 }
1 public class Player { 2 private SetplayingMusicSet = null; 3 4 public Set getPlayingMusicSet() { 5 return this.playingMusicSet; 6 } 7 8 public void setPlayingMusicSet(Set playingMusicSet) { 9 this.playingMusicSet = playingMusicSet; 10 } 11 }
则可这样配置Bean:
1 <beans /* 省略命名空间和XSD模式文件声明 */> 2 <bean id="music_1" class="com.dream.Music" /> 3 <bean id="music_2" class="com.dream.Music"> 4 <property name="musicNameSet"> 5 <set> 6 <value>执着value> 7 <value>一生有你value> 8 set> 9 property> 10 bean> 11 <bean id="player" class="com.dream.Player"> 12 <property name="playingMusicSet"> 13 <set> 14 <ref bean="music_1" /> 15 <ref bean="music_2" /> 16 set> 17 property> 18 bean> 19 beans>
可以看到Set类型的集合能用
1 <beans /* 省略命名空间和XSD模式文件声明 */ 2 xmlns:util="http://www.springframework.org/schema/util" 3 xsi:schemaLocation=" 4 /* 省略命名空间和XSD模式文件声明 */ 5 http://www.springframework.org/schema/util 6 http://www.springframework.org/schema/util/spring-util.xsd"> 7 8 <bean id="music_1" class="com.dream.Music" /> 9 <bean id="music_2" class="com.dream.Music"> 10 <property name="musicNameSet" ref="utilMusicNameSet"/> 11 bean> 12 <bean id="player" class="com.dream.Player"> 13 <property name="playingMusicSet" ref="utilPlayingMusicSet" /> 14 bean> 15 16 <util:set id="utilMusicNameSet"> 17 <value>执着value> 18 <value>一生有你value> 19 util:set> 20 <util:set id="utilPlayingMusicSet"> 21 <ref bean="music_1" /> 22 <ref bean="music_2" /> 23 util:set> 24 25 beans>
可以看到spring-util.xsd模式文件定义了
假如com.dream包现有这样一些类:
1 public class Music { 2 private MapmusicNameMap = null; 3 4 public Map getMusicNameMap() { 5 return this.musicNameMap; 6 } 7 8 public void setMusicNameMap(Map musicNameMap) { 9 this.musicNameMap = musicNameMap; 10 } 11 }
1 public class Player { 2 private MapplayingMusicMap = null; 3 4 public Map getPlayingMusicMap() { 5 return this.playingMusicMap; 6 } 7 8 public void setPlayingMusicMap(Map playingMusicMap) { 9 this.playingMusicMap = playingMusicMap; 10 } 11 }
则可这样配置Bean:
1 <beans /* 省略命名空间和XSD模式文件声明 */> 2 <bean id="music_1" class="com.dream.Music" /> 3 <bean id="music_2" class="com.dream.Music"> 4 <property name="musicNameMap"> 5 <map> 6 <entry key="执着" value="执着" /> 7 <entry key="一生有你" value="一生有你" /> 8 map> 9 property> 10 bean> 11 <bean id="player" class="com.dream.Player"> 12 <property name="playingMusicMap"> 13 <map> 14 <entry key-ref="music_1" value-ref="music_1" /> 15 <entry key-ref="music_2" value-ref="music_2" /> 16 map> 17 property> 18 bean> 19 beans>
可以看到Map类型的集合能用
1 <beans /* 省略命名空间和XSD模式文件声明 */ 2 xmlns:util="http://www.springframework.org/schema/util" 3 xsi:schemaLocation=" 4 /* 省略命名空间和XSD模式文件声明 */ 5 http://www.springframework.org/schema/util 6 http://www.springframework.org/schema/util/spring-util.xsd"> 7 8 <bean id="music_1" class="com.dream.Music" /> 9 <bean id="music_2" class="com.dream.Music"> 10 <property name="musicNameMap" ref="utilMusicNameMap"/> 11 bean> 12 <bean id="player_1" class="com.dream.Player"> 13 <property name="playingMusicMap" ref="utilPlayingMusicMap" /> 14 bean> 15 16 <util:map id="utilMusicNameMap"> 17 <entry key="执着" value="执着" /> 18 <entry key="一生有你" value="一生有你" /> 19 util:map> 20 <util:map id="utilPlayingMusicMap"> 21 <entry key-ref="music_1" value-ref="music_1" /> 22 <entry key-ref="music_2" value-ref="music_2" /> 23 util:map> 24 25 beans>
可以看到spring-util.xsd模式文件定义了
延迟装配
按照正常流程,Spring容器完成Bean的创建之后,开始通过Bean的属性注入Bean的依赖,完成Bean的装配。可是有时候,我们并不希望Spring容器完成Bean的创建之后立即注入依赖,而是希望等到用到的时候才开始注入。这时,就需要用到延迟装配,告诉Spring容器等到用到Bean的时候,才开始注入Bean所需的依赖。如下所示:
1 <beans /* 省略命名空间和XSD模式文件声明 */> 2 <bean id="music" class="com.dream.Music" lazy-init="true"> 3 <property name="musicName" value="执着"/> 4 bean> 5 <bean id="player" class="com.dream.Player" lazy-init="true"> 6 <property name="playingMusic" ref="music"/> 7 bean> 8 beans>
这段配置用到
另外,我们还可设置根元素
1 <beans default-lazy-init="true" 2 /* 省略命名空间和XSD模式文件声明 */> 3 <bean id="music" class="com.dream.Music"> 4 <property name="musicName" value="执着"/> 5 bean> 6 <bean id="player" class="com.dream.Player"> 7 <property name="playingMusic" ref="music"/> 8 bean> 9 beans>
指定ID
一直以来,我们都用
1 <bean id="music_1" name="music_2,music_3,music_4" class="com.dream.Music"/>
我们指定id属性的值为music_1,指定name属性的值为 music_2,music_3,music_4 。因此,该Bean具有四个唯一标识符:music_1,music_2,music_3和music_4。同时我们也注意到了,id属性和name属性有个重大差别:id属性只能指定一个唯一标识符;name属性则不同,可以同时指定多个唯一标识符,标识符之间只要使用逗号,分号或空格隔开就行。
除此之外,Spring还提供了
1 <bean id="music_1" class="com.dream.Music"/> 2 <alias name="music_1" alias="music_2" />
至此,我们完成了关于如何配置Bean的更多介绍。下章该谈谈自动装配时,Bean的歧义应该如何解决那些事了。欢迎大家继续阅读,谢谢大家!
下载代码