Spring的三种主要装配机制
- 在XML中进行显示配置
- 在Java中进行显示配置
- 隐式的bean发现机制和自动装配
- 组件扫描
- 自动装配
@ComponentScan
注解默认会扫描配置类所在的包
@Component
@componentScan
public Class CDPlayerConfig {
}
相同的功能用xml配置的话 使用Spring context命名空间1的<context:component-scan>
元素
<context:component-scan base-package="org.springsz.chapter2"/>
有多个基础包时用,隔开
<context:component-scan base-package="org.springsz.chapter1, org.springsz.chapter2"/>
测试:
新建测试类CDPlayerTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDTest {
@Autowired
private CompactDisc cd;
@Test
public void cdShouldNotBeNull() {
Assert.assertNotNull(cd);
}
}
使用Spring
的SpringJUnit4ClassRunner
,以便在测试开始的时候自动创建Spring的应用上下文
@ContextConfiguration
告诉需要在CDPlayerConfig
中加载配置,因为CDPlayerConfig
中包含@ComponentScan
,所以最终应用上下文包含CompactDisc
bean
@Component("lonelyHeartsClub") //为组件扫描的bean命名
@Component //默认扫描本类所在的包
@Component("soundsystem") //设置扫描的基础包
@Component(basePackages = "soundsystem")
@Component(basePackages = {"soundsystem", "video"}) //设置多个基础包
@Component(basePackageClasses = {CDPlayer.class, DVDPlayer.class}) //设置类所在的包为基础包
@Autowired
注解可以用在属性、构造器、方法上,如果没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出异常
@Autowired(required=false)
没有匹配的bean的时候不会抛异常
如果有多个bean满足依赖关系,会抛出异常
- 书里面是提倡用Spring自动装配bean、JavaConfig显示装配bean
- 上面是自动装配的例子,下面这个是显示装配的例子
- 比如要使用第三方库中的组件,没办法添加@Componen和@Autowired注解,可以使用JavaConfig显示配置bean
@Bean
注解会告诉Spring这个方法会返回一个对象,注册为Spring应用上下文中的bean
@Bean //@Bean("lonelyHeartsClubBand")
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
······························································
@Configuration
@ComponentScan
public class CDPlayerConfig { //创建配置类
@Bean //返回对象注册到Spring应用上下文中
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
}
默认bean的id是方法名,可以设置别名
Spring将会拦截对@Bean
注解方法的调用,并确保直接返回该方法所创建的bean,而不是每次都对其进行实际的调用。
@Configuration
@ComponentScan
public class CDPlayerConfig {
@Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
@Bean
public CDPlayer anotherCdPlayer() {
return new CDPlayer(sgtPeppers());
}
@Bean
public CDPlayer cdPlayer(CompactDisc cd) { //当Spring调用此方法时,会自动装配一个CompactDisc到配置方法中,不用明确引用CompactDisc的@Bean方法
return new CDPlayer(cd);
}
}
作为起步,在JavaConfig中所需要的只是@Configuration
,
在XML中需要在顶部声明多个XML模式(XSD)文件,这些文件定义了配置Spring的XML元素。
<bean class="soundsystem.SgtPeppers" /> //默认ID是:soundsystem.SgtPeppers#0,#0是一个计数形式,用来区分相同类型的其他bean,#1
<bean id="sgtPeppers" class="soundsystem.SgtPeppers" />
Spring发现<bean>
,会调用默认构造器创建bean
<!--注入bean-->
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="sgtPeppers" />
</bean>
<!--还可以使用c-命名空间,需要顶部模式声明-->
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:cd-ref="sgtPeppers"></bean>
<!--c 代表c命名空间前缀-->
<!--cd 代表构造器参数名-->
<!--ref 代表注入bean引用-->
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:_0-ref="sgtPeppers"></bean>
<!--_0 表示参数索引-->
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:_-ref="sgtPeppers"></bean>
<!--只有一个参数可以只写_-->
不使用ref引用其他bean的例子:
首先有个类
public class BlankDisc implements CompactDisc {
private String title;
private String artist;
public BlankDisc(String title, String artist) {
this.title = title;
this.artist = artist;
}
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
······································································
<bean id="blankDisc" class="soundsystem.BlankDisc">
<constructor-arg value="" />
<constructor-arg value="" />
</bean>
或
<bean id="blankDisc" class="soundsystem.BlankDisc" c:_title="" c:_artist="" />
或
<bean id="blankDisc" class="soundsystem.BlankDisc" c:_0="" c:_1="" />
<!--在装配集合参数时,只能使用<constructor-arg>-->
<constructor-arg>
<list>
<value>aabbccdd</value>
</list>
</constructor-arg>
或
<constructor-arg>
<list>
<ref bean="sgtPeppers" />
</list>
</constructor-arg>
将<list>换为<set>也一样
<!--还可以将null传给构造器-->
<constructor-arg><null/></constructor-arg>
以上的注入都是XML使用构造器的注入
下面是属性注入
<bean id="blankDisc" class="soundsystem.BlankDisc">
<property name="title" value="" />
</bean>
<bean id="cdPlayer" class="soundsystem.CDPlayer" >
<property name="cd" ref="sgtPeppers">
</bean>
<!--或者使用p-命名空间-->
<bean id="cdPlayer" class="soundsystem.CDPlayer" p:cd-ref="sgtPeppers" />
<!--对于集合属性,和构造器注入一样-->
<property name="tracks">
<list>
<value>aabbccdd</value>
</list>
</property>
<!--还可以通过使用util-命名空间进行简化-->
<!--同样需要顶部模式声明-->
<!--他会创建一个bean,提供引用-->
<util:list id="trackList">
<value>aabbccdd</value>
</util:list>
<bean id="##" class="##" p:title="##" p:artist="##" p:tracks="trackList" />
<!--util-命名空间还提供其他类型元素-->
<util:map>、<util:set> ......
下面看下Java和XML的混合配置
//假设现在有两个配置类,JavaConfig1和JavaConfig2
@Configuration
public class JavaConfig1 {
}
@Configuration
public class JavaConfig2 {
}
//两个类中相互有bean的引用,现在需要整合两个类
//方法一:
@Configuration
@import(JavaConfig2.class)
public class JavaConfig1 {
}
//方法二:
//新建一个根配置类
@Configuration
@import({JavaConfig1.class, JavaConfig2.class})
public class JavaConfigAll {
}
//如果在Java中需要用到XML中的配置bean:
@Configuration
@import({JavaConfig1.class, JavaConfig2.class})
@importResource("classpath:cd-config.xml")
public class JavaConfigAll {
}
//再假设现在有两个XML配置文件,相互有bean引用,现在要整合
//在config1.xml中:
<import resource="config2.xml" /> //这里我的书上写的是resoune,应该是印错了
//在XML中想要引用JavaConfig的类时,可以使用<bean>元素
//XML中也可以设置一个根配置文件,整合各个XML和JavaConfig
//configAll.xml:
<bean id="" class="" />
<import resource="config1.xml" /> //这里resource书上印对了
<import resource="config2.xml" />
再在根配置中启动组件扫描
** ↩︎