上文中讲的是构造器注入的方式,现在讲如何注入bean的属性。bean的属性是什么,其实就是一个类对应的数据成员。当一个类定义了一个数据成员以后,一般就会有对应于这个数据成员的setXXX()和getXXX()方法,而Spring注入bean属性就是通过setter注入的。
仍然先举一个例子:用Spring配置一个bean,给这个bean注入属性,这个bean指向的类里有一个方法,用来描述一下动作:java学习者在写30篇博客同时还在听歌。
首先还是先写一个主体类:SongJavaer2.java
package com.springinaction.springidol;
/** * 听歌的编程者 * @author 白鑫 * @date 2016-1-6下午11:01:14 */
public class SongJavaer2 implements Coder{
private int blogNum;
public void setBlogNum(int blogNum) {
this.blogNum = blogNum;
}
private Song song;
public void setSong(Song song) {
this.song = song;
}
public void perform() {
System.out.println("Trigl is writing " + blogNum + " blogs.");
System.out.println("While listening...");
song.play();
}
}
继承的接口Coder.java见上面,这个类定义了两个数据成员:int类型的blogNum和类Song的对象song,下面我们将实现用Spring将这两个属性注入。
在XML文件中配置bean
<bean id="songJavaer2" class="com.springinaction.springidol.SongJavaer2">
<property name="blogNum" value="30" />
<property name="song" ref="songJay" />
</bean>
<bean id="songJay" class="com.springinaction.springidol.SongJay" />
可以看到,Spring注入属性是通过<bean>
元素的<property>
属性来实现的,其中name的值对应所注入的类的数据成员,也即bean的属性。当注入普通的原始数据成员类型如整型、字符型的时候,是用value来赋值的;当注入另一个bean的引用的时候,是用ref来赋值的。
main方法加载上下文环境进行测试
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"com/springinaction/springidol/spring-idol.xml");
Coder coder = (Coder) ctx.getBean("songJavaer2");
coder.perform();
}
控制台输出结果是:
Trigl is writing 30 blogs.
While listening...
一盏离愁孤灯伫立在窗口
我在门后假装你人还没走
旧地如重游月圆更寂寞
夜半清醒的烛火不忍苛责我
一壶漂泊浪迹天涯难入喉
你走之后酒暖回忆思念瘦
水向东流时间怎么偷
花开就一次成熟我却错过
谁在用琵琶弹奏一曲东风破
岁月在墙上剥落看见小时候
犹记得那年我们都还很年幼
而如今琴声幽幽我的等候你没听过
谁在用琵琶弹奏一曲东风破
枫叶将故事染色结局我看透
篱笆外的古道我牵着你走过
荒烟漫草的年头就连分手都很沉默
一般来说,我们注入属性时引用的bean还可以被其他bean所引用,但是如果我们想单独霸占一个bean,即仅被某一个bean所使用,其他bean无法使用,那该怎么办呢?很简单,直接在<property>
属性里面写一个<bean>
元素即可,但是注意,<bean>
元素里面只有class没有id,当然你也可以写一个id,但是这样完全没有必要,因为这个bean不会被其他bean引用,所以定义了id也不可能用到,例子如下:
<bean id="songJavaer2" class="com.springinaction.springidol.SongJavaer2">
<property name="song">
<bean class="org.springinaction.springidol.SongJavaer" />
</property>
</bean>
而且在构造器注入时也可以这样注入内部bean,如下:
<bean id="songJavaer" class="com.springinaction.springidol.SongJavaer">
<constructor-arg>
<bean class="org.springinaction.springidol.SongJavaer" />
</constructor-arg>
</bean>
上面我们讲了注入简单的值和引用的bean,还有一种复杂的情况就是需要注入这些值或者bean的集合。一般在类中可以选择作为数据成员的集合性的类有以下几种:数组、java.util.Collection、java.util.Set、java.util.List、java.util.Map、java.util.Properties,对应于Spring在XML文件中配置bean的元素有<list>
、<set>
、<map>
、<props>
,具体差别见下表:
集合配置元素 | 可注入的集合类 | 配置说明 |
---|---|---|
<list> |
数组、Collection、Set、List | 允许重复的集合 |
<set> |
数组、Collection、Set、List | 不允许重复的集合 |
<map> |
Map | 对应的key和value可以取任何类型 |
<props> |
Properties | 对应的key和value只可以取String类型 |
细节知识仍然是通过例子来讲解:用Spring配置一个bean,给这个bean注入属性,这个属性要求是集合类,这个bean指向的类里有一个方法,用来描述一下动作:java学习者在听一组歌曲。
首先写主体类SongJavaer3.java
package com.springinaction.springidol;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/** * 唱歌的编程者 * @author 白鑫 * @date 2016-1-6下午11:29:49 */
public class SongJavaer3 implements Coder {
//Collection在XML中对应于<list>或者<set>
private Collection<Song> songCollection;
public void setSongCollection(Collection<Song> songCollection) {
this.songCollection = songCollection;
}
//List在XML中对应于<list>或者<set>
private List<Song> songList;
public void setSongList(List<Song> songList) {
this.songList = songList;
}
//Map在XML中对应于<map>
private Map<String,Song> songMap;
public void setSongMap(Map<String,Song> songMap) {
this.songMap = songMap;
}
//Properties在XML中对应于<props>
private Properties songProperties;
public void setSongProperties(Properties songProperties) {
this.songProperties = songProperties;
}
public void perform() {
System.out.println("Trigl一边写Java博客一边听歌");
System.out.println("————————我是可爱的分割线————————");
System.out.println("播放songCollection中的歌曲......");
System.out.println();
for(Song song : songCollection) {
song.play();
}
System.out.println("————————我是可爱的分割线————————");
System.out.println("播放songList中的歌曲......");
System.out.println();
for(Song song : songList) {
song.play();
}
System.out.println("————————我是可爱的分割线————————");
System.out.println("播放songMap中的歌曲......");
System.out.println();
for(String key : songMap.keySet()) {
System.out.print(key + ":");
Song song = songMap.get(key);
song.play();
}
System.out.println("————————我是可爱的分割线————————");
System.out.println("播放songProperties中的歌曲......");
System.out.println();
for(Iterator it = songProperties.keySet().iterator();it.hasNext();)
{
String key = (String)it.next();//key值
System.out.print(key + ":");
System.out.println(songProperties.getProperty(key));//通过key得到value
System.out.println();
}
}
}
这里写了四个例子,分别为了用于后面讲解四种集合配置元素的使用。
Song1.java
package com.springinaction.springidol;
public class Song1 implements Song {
public void play() {
System.out.println("是他就是他,是他就是他,我们的英雄,小哪吒!......");
System.out.println();
}
}
Song2.java
package com.springinaction.springidol;
public class Song2 implements Song {
public void play() {
System.out.println("让我们荡起双桨,小船儿随风飘荡~......");
System.out.println();
}
}
Song3.java
package com.springinaction.springidol;
public class Song3 implements Song {
public void play() {
System.out.println("梦里梦到醒不来的梦,梦境里被囚禁的红......");
System.out.println();
}
}
XML文件中集合注入元素的具体配置
<bean id="songJavaer3" class="com.springinaction.springidol.SongJavaer3">
<!-- 通过<list>元素注入,可以显示重复的bean -->
<property name="songCollection">
<list>
<ref bean="song1"/>
<ref bean="song2"/>
<ref bean="song3"/>
<ref bean="song3"/>
</list>
</property>
<!-- 通过<set>元素注入,不显示重复的bean -->
<property name="songList">
<set>
<ref bean="song1"/>
<ref bean="song1"/>
<ref bean="song1"/>
</set>
</property>
<!-- 通过<map>元素注入 -->
<property name="songMap">
<map>
<entry key="《哪吒》" value-ref="song1" />
<entry key="《让我们荡起双桨》" value-ref="song2" />
<entry key="《红玫瑰》" value-ref="song3" />
</map>
</property>
<!-- 通过<props>元素注入 -->
<property name="songProperties">
<props>
<prop key="《哪吒》">是他就是他,是他就是他,我们的英雄,小哪吒!......</prop>
<prop key="《让我们荡起双桨》">让我们荡起双桨,小船儿随风飘荡~......</prop>
<prop key="《红玫瑰》">梦里梦到醒不来的梦,梦境里被囚禁的红......</prop>
</props>
</property>
</bean>
<bean id="song1" class="com.springinaction.springidol.Song1" />
<bean id="song2" class="com.springinaction.springidol.Song2" />
<bean id="song3" class="com.springinaction.springidol.Song3" />
<map>
有四个属性值,如下:
属性 | 目的 |
---|---|
key | 指明map的键,取String |
key-ref | 指明map的键,取bean的引用(id) |
value | 指明map的值,取String |
value-ref | 指明map的值,取bean的引用(id) |
main方法中进行测试
package com.springinaction.springidol;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/** * 用来测试的main函数 * @author 白鑫 * @date 2016-1-6下午11:36:08 */
public class MainTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"com/springinaction/springidol/spring-idol.xml");
Coder coder = (Coder) ctx.getBean("songJavaer3");
coder.perform();
}
}
控制台输出为:
Trigl一边写Java博客一边听歌
————————我是可爱的分割线————————
播放songCollection中的歌曲......
是他就是他,是他就是他,我们的英雄,小哪吒!......
让我们荡起双桨,小船儿随风飘荡~......
梦里梦到醒不来的梦,梦境里被囚禁的红......
梦里梦到醒不来的梦,梦境里被囚禁的红......
————————我是可爱的分割线————————
播放songList中的歌曲......
是他就是他,是他就是他,我们的英雄,小哪吒!......
————————我是可爱的分割线————————
播放songMap中的歌曲......
《哪吒》:是他就是他,是他就是他,我们的英雄,小哪吒!......
《让我们荡起双桨》:让我们荡起双桨,小船儿随风飘荡~......
《红玫瑰》:梦里梦到醒不来的梦,梦境里被囚禁的红......
————————我是可爱的分割线————————
播放songProperties中的歌曲......
《让我们荡起双桨》:让我们荡起双桨,小船儿随风飘荡~......
《哪吒》:是他就是他,是他就是他,我们的英雄,小哪吒!......
《红玫瑰》:梦里梦到醒不来的梦,梦境里被囚禁的红......
是的少年,你没有听错,的确是注入空或者说是null。第一个原因是为了初始化属性的值,另一个原因是覆盖自动装配的值,配置方式如下:
<property name="someNonNullProperty"><null/></property>