在XML中进行显式配置
在Java中进行显式配置
隐式的bean发现机制和自动装配
本文主要讲解bean的自动装配
package com.demo;
/**
* CD接口定义了CD的概念
*/
public interface CompactDisc {
/**
* CD可以被播放器播放
*/
void play();
}
package com.demo;
import org.springframework.stereotype.Component;
/**
* 定义了一个具体的CD实现类
*
* @Component 注解表名该类会作为组件类,并告知Spring要为这个类创建bean。
* 不过,组件扫描由于组件扫描默认是不启用的,所以我们还需要显示的配置一下Spring,从而命令它去寻找带有@Component注解的类,并为其创建bean。
*/
@Component
public class Fantasy implements CompactDisc {
private String title = "双截棍";
private String artist = "周杰伦";
@Override
public void play() {
System.out.println("正在播放" + artist + " 的 " + title);
}
}
package com.demo;
import org.springframework.context.annotation.ComponentScan;
/**
* @ComponentScan 注解能够在Spring中启用组件扫描。
* 如果没有其他配置的话,@ComponentScan默认会扫描与配置类相同的包及其子包,查找带有@Component注解的类。
* 这样会在Spring中自动为这些类创建一个bean
*/
@Configuration
@ComponentScan
public class CDPlayerConfig {
}
package com.demo;
import 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(){
Assert.assertNotNull(cd);
}
}
CDPlayerTest使用了Spring的 SpringJUnit4ClassRunner,以便在测试开始的时候自动创建Spring的应用上下文。注解@ContextConfiguration会告诉它需要在CDPlayerConfig中加载配置。因为CDPlayerConfig类中包含了@ComponentScan,因此最终的应用上下文中应该包含CompactDisc bean。
Spring应用上下文中所有的bean都会给定一个ID。上面的Fantasy 类中,Spring会根据类名为其指定一个ID,为fantasy,也就是将类名的第一个字母变为小写。
如果,想为这个bean设置不同的ID,可以在注解上写上属性做为bean的名称,如下:
@Component("双截棍")
public class Fantasy implements CompactDisc {
...
}
除了@Component注解外,还可以用Java依赖注入规范(Java Dependency Injection)中所提供的@Named注解来为bean设置ID,如下:
@Named("双截棍")
public class Fantasy implements CompactDisc {
...
}
目前,以上代码中的@ComponentScan注解还没有设置任何属性,它将会以配置类所在的包做为基础包来扫描组件。
我们还可以设置属性来指定不同的基础包去扫描,如下:
@Configuration
@ComponentScan("com")
public class CDPlayerConfig {
}
如果想更加清晰地表明我们设置的是基础包,可以通过basePackages属性进行配置,如下:
@Configuration
@ComponentScan(basePackages = "com")
public class CDPlayerConfig {
}
还可以设置多个基础包,如下:
@Configuration
@ComponentScan(basePackages = {"com","com1","com2"})
public class CDPlayerConfig {
}
由于我们是通过String来设置的基础包,如果重构代码的话,可能所指定的基础包就会出错误了。所以,这个注解可以通过指定某个包所包含的类或接口的形式,来避免上述问题。如下:
@Configuration
@ComponentScan(basePackageClasses = {CDPlayer.class,DVDPlayer.class})
public class CDPlayerConfig {
}
上面basePackageClasses 属性中的设置的数组包含了类,这些类所在的包将会做为组件扫描的基础包。
自动装配就是让Spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在应用上下文中寻找匹配某个bean需要的其他bean。
我们可以通过Spring的@Autowired注解。
给类构造器上添加@Autowired注解,这表明当Spring创建CDPlayer bean的时候,会通过这个构造器来进行实例化并会传入一个可设置给CompactDisc类型的bean。如下:
@Component
public class CDPlayer implements MediaPlayer{
private CompactDisc cd;
@Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play(){
cd.play();
}
}
如下:
@Autowired
public void setCd(CompactDisc cd) {
this.cd = cd;
}
如下:
@Autowired
public void insertCd(CompactDisc cd) {
this.cd = cd;
}
如上,不管是构造器、Setter方法还是其他的方法,Spring都会尝试满足方法参数上所声明的依赖。加入有且只有一个bean匹配依赖需求的话,那么这个bean将会被装配进来。
如果没有匹配的bean,那么在应用上下文创建的时候,Spring会跑出一个异常。为了避免异常的出现,可以将@Autowired的required属性设置为false,如下:
@Autowired(required = false)
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
此时,Spring将会尝试执行自动装配,但是如果没有匹配的bean的话,Spring将会让这个bean处于未装配的状态。所以这种情况下,如果代码中没有对null检查的话,可能会出现NPE。
如果有多个bean都能满足依赖关系的话,Spring会抛出异常。
同@Named注解一样,@Inject注解也来源与Java依赖注入规范。在自动装配中,Spring同时支持@Inject和@Autowired。如下:
@Named
public class CDPlayer2 {
private CompactDisc cd;
@Inject
public CDPlayer2(CompactDisc cd) {
this.cd = cd;
}
}