在spring中,对象无需自己查找或创建与其所关联的其他对象,容器负责把需要相互协作的对象引用赋予各个对象,容器的这种创建对象之间协作关系的行为被称为装配,也被成为依赖注入(DI),依赖注入有3种方案可供选用,如下
1、在XML中进行显式的配置
2、在Java中进行显式的配置
3、隐式的bean发现机制和自动装配
隐式的bean发现机制和自动装配
看下面一个实例
1、创建一个接口
public interface CompactDisc {
void play();
}
2、添加这个接口的实现,注意我们在类的头部添加了@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);
}
}
3、添加对这个组件的配置,这个类里面什么东西都没有,只有类的头部有两个注解,分别为@Configuration和@ComponentScan,其中@ComponentScan注解表明会对这个包中的包含@Component的类进行扫描
@Configuration
@ComponentScan
public class CDPlayConfig {
}
4、编写一个简单的JUnit例子
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayConfig.class)
public class CDPlayConfigTest {
@Autowired
private CompactDisc cd;
@Test
public void cdShouldNotBeNull(){
assertNotNull(cd);
}
}
在上面的JUnit的例子中,类的头部包含了@RunWith注解和@ContextConfiguration注解,其中RunWith中的SpringJUnit4ClassRunner.class将会为我们创建Spring应用的上下文,ContextConfiguration中的classes = CDPlayConfig.class则表明我们将在CDPlayConfig中加载配置
运行,会发现JUnit的测试是通过的
为被装配的组件命名
Spring应用的上下文中的所有的bean都会有一个ID来标识自己,假如我们不强制指定,那么Spring会根据类名为其指定一个ID,一般会把类的第一个字母小写来作为ID,比如上面的SgtPeppers
,那么这个bean的ID就是sgtPeppers
,我们也可以自己指定ID,有两种方式,分别如下
第一种是在Component里面直接写上ID
@Component("lonelyHeartClub")
public class SgtPeppers implements CompactDisc {
...
}
第二种是使用DI的参数@Named注解,如下
@Named("lonelyHeartClub")
public class SgtPeppers implements CompactDisc {
...
}
不过推荐使用第一种
对于@ComponentScan的注解,假如我们不指定扫描的包,那么就会扫描配置类当前所在的包,我们也可以指定我们需要进行扫描的包,如下
@ComponentScan(basePackages = "com.fan.soundsystem")
public class CDPlayConfig {
}
不过也可以使用类所在包作为扫描的包,如下
@Configuration
@ComponentScan(basePackageClasses = CDPlayConfig.class)
public class CDPlayConfig {
}
@Autowired是自动装配注解,表明会在上下文中搜索bean并装配到参数之中,假如没有匹配的bean,那么就会抛出异常,为了避免异常的发生,我们可以设置@Autowired的required属性为false。我们同样可以使用@Inject来替代@Autowired,如下
@Inject
public void setCompactDisc(CompactDisc cd){
this.cd = cd;
}
通过JavaConfig进行bean的装配
1、我们针对CompactDisc创建一个新的实现
@Component
public class Revolver implements CompactDisc {
private String title = "Revolver";
private String artist = "The Beatles";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
2、然后我们把CDPlayConfig 中的@ComponentScan注解移除,并添加我们自己写的注入,需要注意的是,假如我们有两个创建CompactDisc 的方法被增加了注解@bean,那么我们将得不到一个正确的结果,如下面注释的部分不能出现
@Configuration
public class CDPlayerConfig1 {
// @Bean
// public CompactDisc sgtCompactDisc(){
// return new SgtPeppers();
// }
@Bean
public CompactDisc randomBeatlesCD(){
int choice = (int) Math.floor(Math.random() * 4);
if(choice == 0){
return new SgtPeppers();
}else {
return new Revolver();
}
}
@Bean
public CDPlayer cdPlayer(){
return new CDPlayer(randomBeatlesCD());
}
}
3、对JUnit的实例做一下简单的修改
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig1.class)
public class CDPlayConfigTest {
// @Rule
// public final StandardOutputStreamLog log = new
@Autowired
private CDPlayer cd;
@Test
public void cdShouldNotBeNull(){
assertNotNull(cd.getCompactDisc());
}
这样同样能够取得相同的效果
通过XML进行bean的装配
基于XML装配bean的方法配置风格有两种,分别为
<constructor-arg>元素
使用Spring3.0所引入的c空间
使用<constructor-arg>的配置文件如下所示
<?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 id="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
<bean id="cdPlayer" class="com.fan.soundsystem.CDPlayer">
<constructor-arg ref="compactDisc"/>
</bean>
</beans>
我们可以通过这种方式来获取bean
使用c命名空间的方式配置如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
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 id="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
<bean id="cdPlayer" class="com.fan.soundsystem.CDPlayer" c:cd-ref="compactDisc"/>
</beans>
我们为上面的配置编写一个测试方法,如下
public class Main {
public static void main(String[] args){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
CDPlayer cd = context.getBean(CDPlayer.class);
cd.getCompactDisc().play();
context.close();
}
}
c命名空间相比之下更加的灵活
我们有时候需要将字面量注入到bean之中,我们在这种情况下该怎么做呢?
如下,我们先创建一个类,并不设置任何注解
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;
}
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
for(String track : tracks)
System.out.println("-Track:" + track);
}
}
然后利用配置给这个bean进行配置
<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Clubs Band"/>
<constructor-arg value="The Beatles"/>
<constructor-arg>
<list>
<value>Sgt. Peper's Lonely Hearts Club Band</value>
<value>Fixing a Hole</value>
</list>
</constructor-arg>
</bean>
和引用注入一样,我们同样可以使用c命名空间进行注入,如下
<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc"
c:title="Sgt. Pepper's Hearts Club Band"
c:artist="The Beatles"
c:tracks-ref="trackList"/>
以上都是构造器注入的方法,有时候我们需要对属性进行注入,那么我们可以使用下面这种方式,首先我们需要改造一下BlankDisc的写法
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 setTitle(String title){this.title = title;}
public void setArtist(String artist){this.artist = artist;}
public void setTracks(List<String> tracks){this.tracks = tracks;}
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
for(String track : tracks)
System.out.println("-Track:" + track);
}
}
注意其中的构造器必须注释掉,否则会出错,然后我们对配置文件进行编写
<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc">
<property name="title" value="Sgt. Pepper's Lonely Hearts Club Band"/>
<property name="artist" value="The Beatles"/>
<property name="tracks">
<list>
<value>Getting Better</value>
<value>Fixing a Hole</value>
</list>
</property>
</bean>
同样,我们还可以使用p空间进行配置,看下面
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
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
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
<util:list id="trackList">
<value>Getting Better</value>
<value>Fixing a Hole</value>
</util:list>
<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc"
p:title="Sgt. Pepper's Lonely Hearts Club Band"
p:artist="The Beatles"
p:tracks-ref="trackList"/>
</beans>
混合配置
在通常的使用中,我们不仅可以使用上面3中方式的任何一种,而且我们还可以将各种方式进行组合使用,常见的做法是在JavaConfig中引用XML和在XML中引用JavaConfig,那么我们应该怎么做才能达到这一点呢
JavaConfig中引用XML
假如我们在一个测试单元中同事使用CDPlayer和BlankDisc,那么我们可以对CDPlayerConfig1 增加对BlankDisc的配置,如下所示
@Configuration
@ImportResource("classpath:springConfig.xml")
public class CDPlayerConfig1 {
// @Bean
// public CompactDisc sgtCompactDisc(){
// return new SgtPeppers();
// }
@Bean
public CompactDisc randomBeatlesCD(){
int choice = (int) Math.floor(Math.random() * 4);
if(choice == 0){
return new SgtPeppers();
}else {
return new Revolver();
}
}
@Bean
public CDPlayer cdPlayer(){
return new CDPlayer(randomBeatlesCD());
}
}
我们再修改一下测试单元的代码,如下
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig1.class)
public class CDPlayConfigTest {
// @Rule
// public final StandardOutputStreamLog log = new
@Autowired
private CDPlayer cd;
@Autowired
private BlankDisc bd;
@Test
public void cdShouldNotBeNull(){
assertNotNull(cd.getCompactDisc());
assertNotNull(bd);
}
}
运行并查看运行的结果,如下所示
XML中引用JavaConfig
我们先创建一个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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="springConfig.xml"/>
<bean class="com.fan.soundsystem.CDPlayerConfig1"/>
</beans>
再编写测试文件,如下
public static void main(String[] args){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("TotalConfig.xml");
AnnotationConfigApplicationContext context1 = new AnnotationConfigApplicationContext(CDPlayerConfig1.class);
BlankDisc bd = context.getBean(BlankDisc.class);
CDPlayer cdPlayer1 = context1.getBean(CDPlayer.class);
// CDPlayer cdPlayer = context1.getBean(CDPlayer.class);
cdPlayer1.play();
bd.play();
context.close();
}
运行并查看结果
网友评论