自动装配
自动装配(autowiring):Spring自动满足bean之间的依赖。
隐式配置和自动装配组合在一起能发挥出强大的威力,它们能够将你的显式配置降低到最少。
用法:
现在需要构造一个Bean:person,Person类中含有Cat类型的成员变量(容器中已存在一个Cat类型的Bean:cat),利用@Autowired注解,Spring可以自动地将容器中的cat装配给这个成员变量
@Component
public class Cat { }
@Component
public class Person {
@Autowired
private Cat cat; //利用@Autowired自动装配
...
}
原理:
在Spring创建对象的过程中,会为类里标有@Autowired注解的地方,默认按类型 (byType) 从容器中匹配一个bean注入进去
1、@Autowired注解可以标注的地方:成员变量上、构造器上、方法上
- 用在成员变量上:
@Autowired
private UserService userService; //Spring在容器中匹配一个类型为UserService的bean注进去
- 用在构造器上:
private Book book;
@Autowired
public Student(Book book) { //Spring会优先使用带有@Autowired的构造方法实例化对象(Bean的生命周期:构造方法的推断),方法使用的参数:在容器中匹配一个类型为Book的bean注进去
this.book = book;
}
- 用在方法上(普通方法也可以,不一定非是set方法):
@Autowired
public void setBook(Book book) {
this.book = book;
}
问题1:
■ 若当前容器中没有匹配类型的bean,就会抛出异常。为了避免异常的出现,可以将@Autowired的required的值设为 false。
@Autowired(required = false)
private Book book;
将required属性设置为false时,Spring尝试自动装配,若没有该类型的bean,Spring将会让这个属性处于未装配的状态。
但是,把required属性设置为false时,你需要谨慎对待。如果在你的代码中没有进行null检查的话,那么这个处于未装配状态的属性有可能会出现NullPointerException
问题2:
■ 若容器中匹配到一个类型的多个bean怎么办?
例:类Food中,有一个Dessert属性,我们希望利用自动装配来完成此属性的赋值
@Component
public class Food {
@Autowired
private Dessert dessert;
...
}
Dessert是一个接口,有三个实现类,分别为Cake、Cookies和IceCream
@Component
public class Cake implements Dessert {..}
@Component
public class Cookies implements Dessert {..}
@Component
public class IceCream implements Dessert {..}
Spring会按Dessert类型 (byType) 查找容器,但是查找到三个bean:cake、cookies、iceCream 。这时,出现了歧义性问题:应该选择哪个bean注入呢?
其实,若查找到了多个bean,Spring会再按变量名字 (dessert)进行查找,当然,当前容器中是没有 dessert 的。这时就会抛出异常:NoUniqueBeanDefinitionException。
对此,我们有两种解决方法:
方法一:使用@Primary
设置首选bean
@Component
@Primary //若有多个bean符合,则"优先"选择这个bean
public class iceCream implements Dessert {..}
如果你使用的是Java配置显式地声明IceCream,那么@Bean方法应该如下所示:
@Bean
@Primary
public Dessert iceCream(){
return new IceCream()
}
如果你使用的是XML显示地声明IceCream,那么标签应该如下所示:
<bean id="icecream" class="com.desserteater.IceCream" primary="true"/>
不管采用什么方式来标示首选bean,效果都是一样的,都是告诉Spring在遇到歧义性的时候要选择首选的bean。当然,要注意:只能指定一个Primary首选bean,若指定了多个首选bean,则又会出现歧义性问题
方法二:使用@Qualifier
限定符
@Component
public class Food {
@Autowired
@Qualifier("cold") //限定:注入一个"冷的"甜品
private Dessert dessert;
...
}
@Qualifier是可以与@Component、@Bean等一起结合使用的
@Component
@Qualifier("soft") //"软的"
public class Cake implements Dessert {..}
@Component
@Qualifier("crispy") //"脆的"
public class Cookies implements Dessert {..}
@Component
@Qualifier("cold") //"冷的"
public class IceCream implements Dessert {..}
@Bean
@Qualifier("soft")
public Dessert cake(){
return new Cake()
}
@Bean
@Qualifier("crispy")
public Dessert cookie(){
return new Cookies()
}
@Bean
@Qualifier("cold")
public Dessert iceCream(){
return new IceCream()
}
参考书籍:《Spring实战 第4版》