Spring自动装配bean属性

节选自《Spring in Action》64-69页

package com.sflik.bean;

/**
 * Created by sflik on 2015/7/14.
 * 诗接口
 */
public interface Poem {
    void recite();//朗诵
}

 

package com.sflik.bean;

/**
 * 短诗
 * Created by sflik on 2015/7/14.
 */
public class Sonnet29 implements Poem{

    private static String[] LINES={"鹅鹅鹅,曲项向天歌,白毛浮绿水,红掌拨清波"};

    @Override
    public void recite() {
        for (int i = 0; i < LINES.length; i++) {
            System.out.println(LINES[i]);
        }
    }
}

 


package com.sflik.bean;

/**
* Created by sflik on 2015/7/14. * 乐器接口 */ public interface Instrument { public void play(); }

 


package com.sflik.bean;

/**
* Created by sflik on 2015/7/14. * 萨克斯 */ public class Saxophone implements Instrument { public Saxophone(){ } @Override public void play() { System.out.println("TOOT TOOT TOOT !"); } }

 

package com.sflik.bean;

/**
 * 钢琴
 * Created by sflik on 2015/7/14.
 */

public class Piano implements Instrument {

    @Override
    public void play() {
        System.out.println("PLINK PLINK PLINK !");
    }
}

 


package com.sflik.bean;

/*
*表演者接口 */ public interface Performer { void perform(); }

 


package com.sflik.bean;
/**
 * Created by sflik on 2015/7/14.
 * 演奏家出场
 */
public class Instrumentalist implements Performer {

    private String name;
    private String song;
    private Instrument instrument;
  public Instrumentalist() {

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSong() {
        return song;
    }

    public void setSong(String song) {
        this.song = song;       //注入歌曲
    }

    public String screamSong() {
        return song;
    }

    public void setInstrument(Instrument instrument) {
        this.instrument = instrument;  //注入乐器
    }


    @Override
    public void perform() {
        System.out.print(name + " 演奏 " + song + ":");
        instrument.play();
    }
}

 

package com.sflik.bean;

/**
 杂技师
 */
public class Juggler implements Performer {


    private int beanBags = 3;

    public Juggler() {

    }

    //构造注入
    public Juggler(int beanBags) {
        this.beanBags = beanBags;
    }

    @Override
    public void perform() {
     System.out.println("JUGGLING "+beanBags+" BEANBAGS");
    }

}

 

package com.sflik.bean;

/**
 * Created by sflik on 2015/7/14.
 * 诗意的杂技师
 */
public class PoeticJuggler extends Juggler {
    private Poem poem;


    public PoeticJuggler(Poem poem) {
        super();//调用父类无参构造,3个豆袋子
        this.poem=poem;
    }

    public PoeticJuggler(Poem poem, int beanBags) {
      super(beanBags);
      this.poem=poem;
    }

    //重写父类表演方法
    @Override
    public void perform(){
        super.perform();
        System.out.println("While reciting");
        poem.recite();

    }


}

 

package com.sflik.test;

import com.sflik.bean.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 测试类
 * Created by sflik on 2015/7/14.
 */
public class Test {
    static ApplicationContext a = new ClassPathXmlApplicationContext("spring-config.xml");  

    public static void instrumentailistPlay() {
        Performer p = (Performer) a.getBean("kenny2");
        p.perform();
    }

    public static void main(String[] args) {

        instrumentailistPlay();
    }
}

 

    byName自动装配

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">


    <!--萨克斯bean-->
    <bean id="instrument" class="com.sflik.bean.Saxophone"/>

     <!--钢琴bean-->
     <bean id="piano" class="com.sflik.bean.Piano"/>
 

    <!--自动装配 byName-->
    <!--byName装配:寻找上下文中id为instrument的bean和该bean的instrument属性名称匹配,
如果上下文中存在,就把那个bean(id="instrument")装配到该Bean的instrument 属性中
--> <!--注:通过setter注入来进行自动装配--> <bean id="kenny" class="com.sflik.bean.Instrumentalist" autowire="byName"> <property name="song" value="summer"/> <property name="name" value="kenny"/> </bean>
</beans>

 

    byType自动装配

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

     <!--萨克斯bean-->
     <bean id="saxphone" class="com.sflik.bean.Saxophone"/>

     <!--钢琴bean-->
     <bean id="piano" class="com.sflik.bean.Piano"/>
 
     <!--自动装配 byType-->
     <!--byName装配:和byName相似,寻找上下文中id为instrument的bean和该bean的instrument类型匹配,
如果上下文中存在,就把那个bean(id="instrument")装配到该Bean的instrument 属性中
-->
<!--byTpye同样使用setter注入进行自动装配--> <bean id="kenny3" class="com.sflik.bean.Instrumentalist" autowire="byType"> <property name="song" value="summer"/> <property name="name" value="kenny3"/>
</bean>
</beans>

 然。。。。这样编译会报错

因为上下文中存在多个Bean(saxphone,piano)的类型是Instrument的子类

      为了避免因为使用byType自动装配而带来的歧义,Spring为我们提供了另外两种选择:

可以使用<bean>元素的primary属性,为自动装配标识一个首选Bean,或者可以消除某个Bean自动装配的候选资格。

    但是primary属性有个很怪异的一点:它默认设置为true,这意味着所有候选Bean都变成首选Bean,那设置这个属性还有什么意义,所以为了使用primary属性,我们不得不将所有非首选Bean的primary属性设置为false.

  例如:

<bean id="saxphone" class="com.sflik.bean.Saxophone" primary="false" />

 

 primary属性仅对标识首选Bean有意义,如果在自动装配时,我们希望排除某些Bean,那可以设置这些Bean的autowire-candidate属性为flase,如:

<bean id="saxphone" class="com.sflik.bean.Saxophone" autowire-candidate="false" />

这样spring在自动装配时忽略(saxphone)Bean作为候选Bean.

 

    constructor自动装配

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

  <!--短诗bean-->
    <bean id="sonnet29" class="com.sflik.bean.Sonnet29"/>

  <!--诗意的杂技师bean-->
    <bean id="duke" class="com.sflik.bean.PoeticJuggler">
        <!--配置构造参数-->
        <constructor-arg value="100"/>
        <constructor-arg ref="sonnet29"/>
    </bean>

</beans>

以前我们这样写,使用<constructor-arg>元素为Bean的构造器的参数注入值

 

     使用constructor自动装配的话,可以移除<constructor-arg>元素,由spring上下文自动选择Bean注入到构造器的参数中,重新声明的(duck)Bean:

 <bean id="duke" class="com.sflik.bean.PoeticJuggler" autowire="constructor"/>

     在duke Bean的新声明中,<constructor-arg>元素消失不见了,而autowire的属性设置为constructor。上述声明告诉Spring去审视PoeticJuggler的构造器,并尝试在Spring配置中寻找匹配PoeticJuggler某一构造器所有参数的Bean,上面我们定义了sonnet29 Bean,他是一个Poem,恰巧与PoeticJuggler的其中一个构造器参数相匹配,因此当duke Bean时,Spring使用这个构造器,并把sonnet29 Bean作为参数传入。

     constructor自动装配具有和byType自动装配相同的局限性。当发现多个Bean都匹配某个构造器的参数时,Spring不会猜测哪一个Bean更合适自动装配。此外,如果一个类有多个构造器,他们都满足自动装配的条件时,Spring也不会尝试猜测哪一个构造器更适合使用

   

    autodetect最佳自动装配

        如果想自动装配Bean,但是又不能决定该使用哪一种类型的自动装配。现在不用担心了,我们可以设置autowire属性为autodetect,由Spring来决定。例如:

 <bean id="duke" class="com.sflik.bean.PoeticJuggler" autowire="autodetect"/>

   当配置一个Bean的autowire属性为autodetect时,Spring会首先尝试使用constructor自动装配,如果没有发现与构造器相匹配的Bean时,Spring讲尝试使用byType自动装配。

   

   默认自动装配

      如果需要为Spring应用上下文的每一个Bean(或者其中的大多数)配置相同的autowire属性,那么就可以要求Spring为它所创建的所有Bean,应用相同的自动装配策略来简化配置。我们所需要做的仅仅是在根元素<beans>上增加一个default-autowire属性:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byType">

</beans>

    默认情况下,default-autowire属性被设置为none,在这里我们讲default-autowire属性设置为byType,希望每一个Bean都使用byType自动装配。

    我们还可以使用<bean>元素的autowire属性来覆盖<beans>元素所配置的默认自动装配策略    

 

 

 

    

 

posted @ 2015-09-14 17:04  sflik  阅读(340)  评论(0编辑  收藏  举报