- bean的常见三种装配
1.在XML中显示配置
2.在Java中进行显示配置
3.隐式的bean发现机制和自动装配。
- 自动化装配Bean
Spring从两个角度来实现自动化装配:
1.组件扫描(component scanning): Spring会自动发现应用上下文中所创建的bean.
2.自动装配(autowiring):Spring自动满足bean之间的依赖。
(1)创建可被发现的bean
其中的@Component注解,表明这个类为组件类,并且告诉Spring为这个类创建bean。
package soundsystem;
import org.springframework.stereotype.Component;
@Component
public class SgtPeppers implements CompactDisc{
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
因为组件默认是不启用的,因此必须显示配置Spring,从而命其去寻找带有@Component注解的类,并为其创建bean。
@ComponentScan注解是启用组件扫描,其默认扫描与配置类相同的包及其所有的子包,查找带有@Component注解的类。
package soundsystem;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class CDPlayerConfig {
}
xml启用组件的扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/aop/spring-context-2.5.xsd">
<!-- 组件扫描 -->
<context:component-scan base-package="soundsystem" />
</beans>
测试组件能够扫描CompactDisc类
在下面的测试类中使用SpringJUnit4ClassRunner,是为了方便在测试开始的时候自动创建Spring的应用上下文。注解@ContextConfiguration会告诉Spring需要在CDPlayerConfig中加载配置。因为CDPlayerConfig包含了@ComponentScan,因此最终的应用上下文应该包括CompactDiscbean.
@Autowrited注解,是为了将CompactDiscbean注入到测试代码中。
package soundsystem;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerTest {
@Autowired
private CompactDisc cd;
@Test
public void cdShouldNotBeNull() {
assertNotNull(cd);
}
}
(2)位组件扫描的bean命令(个人推荐使用)
Spring会根据类名为其指定一个bean的ID,就是讲类的首字母变为小写。
如果希望自己指定bean的Id。则需要如下这样:lonelyHearsClub为其bean的ID
@Component("lonelyHearsClub")
public class SgtPeppers implements CompactDisc{
}
还有一种如下所示,使用Named。 import javax.inject.Named;
@Named("lonelyHearsClub")
public class SgtPeppers implements CompactDisc{
}
(3)设置组件扫描的基础包
package soundsystem;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("soundsystem")
/***
* 或者@ComponentScan(basePackages="soundsystem")
* 如果是多个基础包
* @ComponentScan(basePackages={"soundsystem","video"})
*/
public class CDPlayerConfig {
}
(4)通过为bean添加注解实现自动装配
package soundsystem;
import javax.inject.Inject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CDPlayer implements MediaPlayer{
private CompactDisc cd;
/**
*
* 构造器注解
* 或者采取@Inject注解如set方法注解一样。Autowired与Inject并没有多大的区别
* 异常:
* 如果没有匹配的bean,那么在Spring应用上下文创建的时候,Spring会抛出一个异常。
* 此时可以讲@Autowired的required属性设置为false。如:@Autowired(required=false)。
* 但是此时必须在代码中支出null检查。否则会抛出NullPointerException.
*/
@Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
/**
* Set方法注解
* @param cd
*/
@Inject
public void setCompactDisc(CompactDisc cd) {
this.cd = cd;
}
@Override
public void play() {
// TODO Auto-generated method stub
}
}
(5)验证自动装配
package soundsystem;
import static org.junit.Assert.*;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerTest {
@Rule
public final StandardOutputStreamLog log = new StandardOutputStreamLog();
@Autowired
private MediaPlayer player;
@Autowired
private CompactDisc cd;
@Test
public void cdShouldNotBeNull() {
assertNotNull(cd);
}
@Test
public void play() {
player.play();
assertEquals("Playing Sgt", log.getLog());
}
}
- 通过Java代码装配bean
因为要明确的将第三方库中的组件装配到自己的应用中,就需要显示的配置。不能使用自动化的配置方案。显示的有两种配置方案:Java和XML。
(1)声明简单的bean
package javaConfig;
import org.springframework.context.annotation.Bean;
public class CDPlayerConfig {
/**
* @Bean注解会告诉Spring这个方法会返回一个对象。该对象要注册为Spring应用上下文中的bean.
* bean的ID与带有@Bean注解的方法名一样。本例中名字是sgtPeppers。
* 如果要设置不同的名字,通过name属性指定一个不同的名字。如@Bean(name="lonlyHeartsClubBand")
* @return
*/
@Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
}
(2)借助JavaConfig实现注入
CDPlayer.java
package javaConfig;
import org.springframework.beans.factory.annotation.Autowired;
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
@Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
}
CDPlayerConfig.java package javaConfig;
import org.springframework.context.annotation.Bean;
public class CDPlayerConfig {
@Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
@Bean
public CDPlayer cdPlayer() {
return new CDPlayer(sgtPeppers());
}
}
默认情况下,Sping中的Bean都是单例的,并没有为第二个CDPlayer创建相同的SgtPeppers实例。因此,Spring会拦截对sgtPeppers()的调用并确保返回的是Spring所创建的bean。sgtPeppers()方法添加了@Bean,Spring将会拦截所有对它的调用,并确保直接返回该方法所创建的bean,而不是每次都对其进行实际的调用。
以传递参数的形式进行创建
/**
* 传参的方式进行,让方法体按照合适的方式调用它。而不需要明确引用CompactDisc的@Bean方法
* @param cd
* @return
*/
@Bean
public CDPlayer cdPlayer(CompactDisc cd) {
return new CDPlayer(cd);
}
以set方法的形式进行传递
/**
* set注入的形式
* @param cd
* @return
*/
@Bean
public CDPlayer cdPlayer(CompactDisc cd) {
CDPlayer cdPlayer = new CDPlayer(cd);
cdPlayer.setCDPlayer(cd);
return new CDPlayer(cd);
}
- 通过XML装配bean
(1)通过构造器注入的形式装配
java类
package xmlCongfig.collections;
import java.util.List;
import soundsystem.CompactDisc;
public class BlankDisc implements CompactDisc {
private String title;
private String artist;
private List<String> tracks;
public BlankDisc(String title, String artist, List<String> tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
}
public void play() {
System.out.println("Playing " + title + " by " + artist);
for (String track : tracks) {
System.out.println("-Track: " + track);
}
}
}
xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!--******************** 构造器类型的DI方式 ******************************* -->
<bean id="compactDisc" class="xmlCongfig.BlankDisc.java">
<!-- 向构造器中传递参数 -->
<constructor-arg value="sgtssss" />
<constructor-arg value="The tsttts" />
<!-- conlection类型的数据传递 -->
<constructor-arg>
<list>
<value>12312</value>
<value>weqe</value>
<value>sda</value>
<value>12</value>
<value>das</value>
<value>21312</value>
</list>
</constructor-arg>
</bean>
<!-- 使用<constructor-arg>标签的形式 -->
<bean id="cdPlayer" class="javaConfig.CDPlayer">
<constructor-arg ref="compactDisc" />
</bean>
<!-- 使用c-命名空前来声明构造器的参数。c:为c-命名空间前缀。cd:构造器参数名。-ref:呼入bean的引用。 compactDisc:要注入的beanID -->
<!-- <bean id="cdPlayer" class="javaConfig.CDPlayer" c:cd-ref="compactDisc"
/> -->
</beans>
(2)通过xml的形式进行装配 java类
package soundsystem.properties;
import org.springframework.beans.factory.annotation.Autowired;
import soundsystem.CompactDisc;
import soundsystem.MediaPlayer;
public class CDPlayer implements MediaPlayer {
private CompactDisc compactDisc;
@Autowired
public void setCompactDisc(CompactDisc compactDisc) {
this.compactDisc = compactDisc;
}
public void play() {
compactDisc.play();
}
}
package soundsystem.properties;
import java.util.List;
import soundsystem.CompactDisc;
public class BlankDisc implements CompactDisc {
private String title;
private String artist;
private List<String> tracks;
public void setTitle(String title) {
this.title = title;
}
public void setArtist(String artist) {
this.artist = artist;
}
public void setTracks(List<String> tracks) {
this.tracks = tracks;
}
public void play() {
System.out.println("Playing " + title + " by " + artist);
for (String track : tracks) {
System.out.println("-Track: " + track);
}
}
}
xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!--******************** set类型的DI方式 ******************************* -->
<bean id="compactDisc" class="xmlCongfig.BlankDisc">
<!--参数的传递-->
<property name="title" value="sda" />
<property name="srts" value="23432" />
<property name="tracks">
<list>
<value>2134234</value>
<value>6</value>
<value>456</value>
<value>23453</value>
<value>652</value>
</list>
</property>
</bean>
<bean id="cdPlayer" class="xmlCongfig.CDPlayer">
<property name="compactDisc" ref="compactDisc" />
</bean>
</beans>
- 导入和混合配置
(1)强两个分开的Configuration类导入到总的Configuration
定义BlankDis的Config类CDConfig。
CDConfig.java
package xmlCongfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CDConfig {
@Bean
public CompactDisc compactDisc() {
return new SgtPeppers();
}
}
定义CDPlayer的Configl类CDPLayerConfig package soundsystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CDPlayerConfig {
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
将两个Configuration类同时导入到总的SoundSystemConfig的类中
package xmlCongfig;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({CDConfig.class,CDPlayerConfig.class})
public class SoundSystemConfig {
}
假如BlankDisc的配置被写在了同目录下的cd-config.xml文件中,则SoundSystemConfig类的配置如下所示。
package xmlCongfig;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSystemConfig {
}
两个bean。一个是配置在JavaConfig中的CDPlayer以及配置在XML中BlankDiSC都会被加载都SPring容器之中。