Spring装配Bean之自动化装配(一)

自动化装配

spring从两个角度来实现自动化装配git

  • 组件扫描: spring会自动发现应用上下文中所建立的bean
  • 自动装配: spring自动知足bean之间的依赖

建立能被spring发现的bean

在须要被发现的类上添加注解@Component

public interface CompactDisc {
	void play();
}
@Component
public class SgtPeppers implements CompactDisc {

	public void play() {
		...
	}
}

使用@Component注解代表该类会做为组件类,并告知spring要为此类建立beanweb

启用组件扫描@ComponentScan

@Configuration
@ComponentScan
public class CDPlayerConfig {
}

若没有其余配置,@ComponentScan 默认会扫描与配置类相同的包,即spring将会扫描此包以及此包下的全部子包,查找带有@Component注解的类,并自动为其建立一个bean.
当使用XML启用组件扫描,可使用spring context命名空间的<context:component-scan base-package="package Name">元素spring

为组件扫描的bean命名

spring应用上下文中全部的bean都会给定一个ID,上述案例中尽管没有明确为bean命名,可是spring会根据类名为其指定一个ID(将类名的第一个字母变为小写),例如SgtPeppers 指定的ID为sgtPeppers.
也能够为此bean设置不一样的Id安全

@Component("testabc")
public class SgtPeppers implements CompactDisc {
	......
}

另外一种为bean命名的方式,不使用@Component注解,而使用Java依赖注入规范(Java Dependency Injection)中提供的@Named注解svg

@Named("abcd")
public class SgtPeppers implements CompactDisc {
	......
}

@Component与@Named在大多数场景中,它们是能够相互替换的,二者之间有一些细微的差别.
查阅了一些资料,稍微了解了一下两者的细微差别:
@Named JSR-330不提供组合模型,@Component是可组合注解
例:学习

// @Named 不能这样组合的
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Named("test")
public class Test  {
	......
}

// @Component 能够组合
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component("test2")
public class Test2  {
	......
}

设置组件扫描的基础包

咱们在启用组件扫描时,用到的@ComponentScan 注解,没有为其设置任何属性,那么,它会按照默认规则,以配置类所在的包做为基础包进行组件扫描.ui

若是咱们将配置类 放在单独的包中,是其与其余应用代码分开,此时默认的基础包就不能知足咱们的需求了.this

这时可使用 @ComponentScanvalue 属性,指明包的名称code

@Configuration
@ComponentScan("autoconfig")
public class CDPlayerConfig {
}

若还想清晰的代表此包为基础包,可使用 basePackages 属性设置component

@Configuration
@ComponentScan(basePackages ="autoconfig")
public class CDPlayerConfig {
}

basePackages 属性是复数形式,因此能够设置扫描多个基础包

@Configuration
@ComponentScan(basePackages ={"autoconfig","autoconfig2"})
public class CDPlayerConfig {
}

basePackages 属性是类型不安全,好比重构代码后,基础包可能会出现错误.
此时可使用 basePackageClasses 属性, 指定为包中所包含的类或接口.

@Configuration
@ComponentScan(basePackageClasses ={CDPlayer.class,DVDPlayer.class})
public class CDPlayerConfig {
}

也能够建立一个用来进行扫描的空标记接口,例如:

public interface TestInterface {
	void play();
}

@Component
public class A implements TestInterface {
	......
}

@Component
public class B implements TestInterface {
	......
}

@Configuration
@ComponentScan(basePackageClasses ={TestInterface.class})
public class TestConfig {
}

为bean添加注解实现自动装配

使用注解@Autowired 实现自动装配,例如在 构造器 上添加此注解

@Component
public class CDPlayer implements MediaPlayer {
	private CompactDisc cd;

	@Autowired
	public CDPlayer(CompactDisc cd) {
		this.cd = cd;
	}

	public void play() {
		cd.play();
	}

}

@Autowired 注解不只能使用在 构造器 上,也能使用在 属性的Setter 方法上

@Autowired
public void setCompactDisc(CompactDisc cd) {
	this.cd = cd;
}

Setter方法并没有特殊之处,@Autowired 注解能够用在类的任何方法上,假设CDPlayer 类有一个insertDisc()方法,@Autowired 注解也能发挥相同的做用.

@Autowried
public void insertDisc(CompactDisc cd) {
	this.cd = cd;
}

无论是构造器,Setter方法,仍是其余方法,spring 都会尝试知足方法参数上所声明的依赖,
有且只有一个bean,那么这个bean将会被装配进来.
若没有匹配的bean,那么在应用上下文建立时,spring会抛出一个异常,此时能够设置@Autowried注解的required属性为false

@Autowired(required=false)
public CDPlayer(CompactDisc cd) {
	this.cd = cd;
}

若将@Autowried注解的required属性设置为false,spring会尝试执行自动装配,但若是没有匹配的bean的话,spring会让这个bean处于未装配状态,若是未在代码中进行null检查,则可能会出现NullPointerException

若是有多个bean都能知足依赖关系,spring将会抛出一个异常,代表没有明确指定要选择哪一个bean进行自动装配.(自动装配中的歧义性)

@Autowried 是spring特有注解,也可使用Java依赖注入规范提供的 @Inject , 两者存在细微差异(这两个的细微差异,暂时没查阅到),但多数状况下均可以相互替换.

源码: https://gitee.com/jincheng-921/sp_ch2_2.git

最近在看spring in action(第4版) ,边看边写点笔记,整理一下,仅供本身学习记录使用,案例是从书中的源码筛选出来的.