节选自《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>元素所配置的默认自动装配策略