第二章 bean捆绑基础(3节)

来源:互联网 发布:apache 禁止目录列表 编辑:程序博客网 时间:2024/04/28 16:17
 
2.3 setter注入bean的属性
典型的,bean提供一对函数用来访问属性的:setXXX()getXXX()Spring利用这点进行setter注入。
为了实力Spring其它方式的DI,下面是另外一个performerKenny是个不错的演奏家,定义如下:
package com.springinaction.springidol;
 
publicinterface Instrument {
    void play();
}
package com.springinaction.springidol;
 
publicclass Instrumentalist implements Performer {
    private String song;
    private Instrument instrument;
   
    public Instrumentalist(){}
   
    publicvoid perform() throws PerformanceException {
       System.out.println("Playing " + song + " : ");
       instrument.play();
    }
 
    public String getSong() {
       returnsong;
    }
    publicvoid setSong(String song) {
       this.song = song;
    }
 
    public Instrument getInstrument() {
       returninstrument;
    }
    publicvoid setInstrument(Instrument instrument) {
       this.instrument = instrument;
    }
}
Kenny可以在bean元素中进行如下定义:
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist">
</bean>
尽管这样kenny就定义好了,但是没有songinstrumentkenny是无法演奏的。下面介绍如何通过setter方法来注入。
2.3.1注入简单的数值
Bean的属性可以通过spring中的property元素来进行配置,propertyconstructor-arg有很多类似的地方。除了一个是通过构造器,一个通过setter方法。
下面看看怎么进行注入
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist">
    <property name="song" value="Jingle Bells"/>
</bean>
一旦Instrumentalist被初始化,Springsetter方法把<property>里面设置的值注入到对象中。这个例子把Jingle Bells放入到kennysong属性中。同一下的代码类似:
Instrumentalist Kenny = new Instrumentalist();
kenny.setSong(“Jingle Bells”);
但这个同spring配置生成有最重要的不同,就是spring提供了代码的松耦合,spring的方法更灵活。
song的属性这个例子中,<property>注入了一个String的类型的值,不过<property>还可以注入别的类型,intfloatbooleanjava.lang.Double等等.
看下面配置:
    <bean id="kenny" class="com.springinaction.springidol.Instrumentalist">
       <property name="song" value="Jingle Bells"/>
       <property name="age" value="37"/>
    </bean>
注意value属性的使用,字段是Stringint没有什么区别,Spring根据字段属性来自动决定正确的类型。因此,ageintSpring自动把37转换成int类型的。
使用<property>来对普通的属性值来赋值非常不错,但DI应该是比这样写在xml文件里更好的东西。DI插入的真实数据是在程序中合作的对象中的,因此它们不需要捆绑在一起。Kenny的程序示例一下如何做。
2.3.2使用其他的bean
Kenny可以使用任何给他的乐器,只要这个乐器继承与Instrument接口。当然,kenny有最喜欢的乐器,saxophone,下面代码定义一个saxophone
package com.springinaction.springidol;
 
publicclass Saxophone implements Instrument {
    public Saxophone() {}
    publicvoid play() {
       System.out.println("TOOT TOOT TOOT");
    }
}
在给kenny演奏前,必须要把它定义一下
<bean id="saxophone" class="com.springinaction.springidol.Saxophone"/>
那么kennybean定义也要修改一下
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist">
    <property name="song" value="Jingle Bells"/>
    <property name="instrument" ref="saxophone"/>
</bean>
现在kenny已经被注入了所有的属性,并且可以开始演出。跟duke一样,我们可以这样来执行:
String path=”com/springinaction/springidol/spring-idol.xml”;
ApplicationContext context = new ClassPathXmlApplicationContext(path);
Performer performer = (Performer)context.getBean(“kenny”);
performer.perform();
这并不是idol比赛,但可以是kenny实验一下,打印输出:
Playing Jingle Bells : TOOT TOOT TOOT
同时,这个例子还展示了一个重要的地方,如果你跟duke执行的代码比较,你发现没什么不一样,但是,唯一的不同点在于,从Spring获得的名字不同。代码是相同的,但产生了一个魔术师,一个演奏者。
这不是spring的优点,而是对接口编程的号称。通过一个Performer接口的对象,我们可以使用任何performer,不论是什么诗人还是弹琴的。Spring因此鼓励使用interface。不过你会看到,面向接口编程和SpringDI是代码更松散。
上面提过,kenny可以演奏各种乐器,现在给他一个钢琴。代码如下:
package com.springinaction.springidol;
 
publicclass Piano implements Instrument {
    public Piano() {}
 
    publicvoid play() {
       System.out.println("PLINK PLINK PLINK");
    }
}
Bean的声明如下
<bean id="piano" class="com.springinaction.springidol.Piano"/>
想让kenny演奏钢琴,kennybean也需要改一下。
    <bean id="kenny" class="com.springinaction.springidol.Instrumentalist">
       <property name="song" value="Jingle Bells"/>
       <property name="instrument" ref="piano"/>
    </bean>
这样,kenny就可以弹钢琴了,代码不需要任何改变。因为Instrumentalist只通过Instrument接口知道它本身的instrument的属性。这样,kenny可以弹saxophone或者piano,两者分散。如果kenny想演奏hammered dulcimer,只需要加入一个类,并且修改xml文件即可。
 
内部类注入
86-87 I don’t care about that. Maybe I will look it later. But not now.
 

2.3.3捆绑集合

到了现在,介绍了spring配置基本类型(通过value)和其他类(通过ref)但valueref只有在你的属性是单一的时候才有效。那么当属性是复数(就是集合)时spring怎么做呢?

Spring提供了4个类型的集合配置元素。参看2.3

 

<list><set>当属性是array或者是一些java.util.Collection时候非常有用。下面会看到,实际实现的用来定义属性的collection,跟使用<list>还是<set>没有任何关系。两个元素都可以不经修改的使用在任何collection上。

对于<map><props>,对应是java.util.Mapjava.util.Properties。这些都是值键对于的一对一对的。唯一两个不同就是props要求值键都是StringMap则没有要求。

下面是在spring中捆绑collectionHank现在来到了SpringIdel舞台。他是一个人的乐队,跟kenny一样,他能够演奏多种乐器,不过hank是同时演奏。Hank的代码如下:

package com.springinaction.springidol;

 

import java.util.Collection;

 

public class OneManBand implements Performer {

    private Collection<Instrument> instruments;

    public OneManBand() {}

 

    public void perform() throws PerformanceException {

       for(Instrument instrument : instruments){

           instrument.play();

       }

    }

 

    public void setInstruments(Collection<Instrument> instruments) {

       this.instruments = instruments;

    }

}

程序中,当OnManBand执行perform方法的时候对collection进行遍历。这里最重要的是instrutment的注入是通过setter方法。看看Spring怎么支持这个collection

 

ListsArrays

Hank要使用乐器,用list来提供给他

    <bean id="hank" class="com.springinaction.springidol.OneManBand">

       <property name="instruments">

           <list>

              <ref bean="guitar"/>

              <ref bean="cymbal"/>

              <ref bean="harmonica"/>

           </list>

       </property>

    </bean>

<list>元素包含1个或多个值。<ref>用来指向在SpringContext里的其它bean的实例,配置了hank可以弹奏guitarcymbalharmonica。这里可以使用其它Spring的赋值的元素,比如<bean>,<value>甚至<null/>。另外,list可以包含另外一个list,多维概念。

OneManBand类的代码中,instruments使用的是jdk1.5java.util.Collection。但<List>用来工作在那些的属性,它们是实现Collection或者是一个数组。就是说,<list>在以下的代码上照常工作

java.util.List<Instrument> instruments;

Instrument[] insruments;

 

Sets

<list>元素更关心的是Spring如何处理这些collection,而不是它的类型。你可以在用到List的地方改用set<set><list>没有的好处:保证每个元素唯一。不一样的元素会被忽略。

<list>一样,<set>的元素类型也是collectionarray

Maps

OneManBand执行时,每种乐器的声音在perform方法中被打印出来。但我们想看到每个音符是哪个乐器弹奏的,代码需要修改一下:

package com.springinaction.springidol;

 

import java.util.Map;

 

public class OneManBand implements Performer {

    private Map<String,Instrument> instruments;

    public OneManBand() {}

 

    public void perform() throws PerformanceException {

       for(String key : instruments.keySet()){

           System.out.println(key + " : ");

           Instrument instrument = instruments.get(key);

           instrument.play();

       }

    }

 

    public void setInstruments(Map<String,Instrument> instruments) {

       this.instruments = instruments;

    }

}

这个代码中,instruments是由键值对组成的,在xml文件中使用下面的定义:

    <bean id="hank" class="com.springinaction.springidol.OneManBand">

       <property name="instruments">

           <map>

              <entry key="GUITAR" value-ref="guitar"/>

              <entry key="CYMBAL" value-ref="cymbal"/>

              <entry key="HARMONICA" value-ref="harmonica"/>

           </map>

       </property>

    </bean>

<map>元素定义了一个map类型,每一个entry元素定义了map的一个成员。上个例子,key定义了键,value-ref定义了引用的beanid

下图是entry里面的元素的含义。

<map>是唯一一个能把不止是String的类型插入的键值对的方法。下面介绍Props

Props

如果键值都是String,那么就要用到java.util.Properties类了。现在把OneManBand修改一下:

package com.springinaction.springidol;

 

import java.util.Iterator;

import java.util.Properties;

 

public class OneManBand implements Performer {

    private Properties instruments;

    public OneManBand() {}

 

    public void perform() throws PerformanceException {

       for (Iterator iter = instruments.keySet().iterator(); iter.hasNext();) {

           String key = (String)iter.next();

           System.out.println(key + " : " + instruments.getProperty(key));

       }

    }

    public void setInstruments(Properties instruments) {

       this.instruments = instruments;

    }

}

Xml中做如下修改

    <bean id="hank" class="com.springinaction.springidol.OneManBand">

       <property name="instruments">

           <props>

              <prop key="GUITAR">STUM STUM STUM</prop>

              <prop key="CYMBAL">CRASH CRASH CRASH</prop>

              <prop key="HARMONICA">HUM HUM HUM</prop>

           </props>

       </property>

    </bean>

This is easy to understand the code, it’s not necessary to talk about it.

有些可能有些混淆,看一下

l         <property>是向bean注入一个值

l         <props>Properties定义的一个元素

l         <prop><props>的一个元素

2.3.4捆绑空值

几乎所有情况,都要把值或者java的引用放入一个bean的属性中,但如果要你放入null呢?

对于properties,可以这样

<property name=”someProperty”><null/></properties>

有时需要用null来覆盖自动捆绑,什么是自动捆绑?下面将会讲述。

 

原创粉丝点击