Spring 基于注解自动装配

1. 基于@Autowired自动装配流程

编写Bean

1
2
3
4
5
6
@Data
@Component // 组件注解
public class Car {
private String name;
private Double price;
}

1
2
3
4
5
6
@Data
@Component // 组件注解
public class Person {
@Autowired // 自动装配注解
private Car car;
}

组件扫描

1
<context:component-scan base-package="demo.spring.bean" />

编写测试方法

1
2
3
4
5
6
@Test
public void test() throws Exception {
ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) ioc.getBean("person");
System.out.println(person.getCar() != null); // true,自动装配成功
}

1.1. 只有Bean组件才能自动装配

如果去掉Person的组件注解,Spring根本就不会去管Person,@Autowired就没有意义了

1
2
3
4
5
6
@Data
// @Component 去掉组件注解
public class Person {
@Autowired // 无意义
private Car car;
}

如果去掉Car的组件注解,也是无法装配成功的

1
2
3
4
5
6
@Data
@Component
public class Person {
@Autowired // NoSuchBeanDefinitionException,找不到类型为Car的组件
private Car car;
}

2. @Autowired原理的简单探索

参考:https://blog.csdn.net/horacehe16/article/details/79811763

@Autowired可以应用于 属性、构造方法、setter等等。但是开发过程中应用于属性是最常见的。时间有限,就先只探索一下@Autowired应用于属性的情况

2.1. 探索:容器中该类型的组件只有一个

修改Person类,修改car属性名,发现自动装配成功,说明容器中同类型组件只有1个时,是根据类型注入,变量名与id不一致也没有关系

1
2
3
4
5
6
@Data
@Component
public class Person {
@Autowired
private Car haha; // 修改属性名,使之与Car组件的id不一致
}

2.2. 探索:容器中该类型的组件有多个

基于注解注册多个Car组件

1
2
3
4
5
6
@Data
@Component
public class Car {
private String name;
private Double price;
}

1
2
3
@Component
public class CarExtend extends Car { // 继承Car
}

基于XML注册多个Car组件

1
2
<bean id="car1" class="demo.spring.bean.Car"/>
<bean id="car2" class="demo.spring.bean.Car"/>

修改Person,使得Car属性名与所有Car组件id不一致

1
2
3
4
5
6
@Data
@Component
public class Person {
@Autowired
private Car haha; // 与所有Car组件的id都不一致
}

运行,抛出异常

1
2
3
4
5
org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'person': Unsatisfied dependency expressed through field 'haha';

nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'demo.spring.bean.Car' available: expected single matching bean but found 2: car,carExtend

修改Person,使得Car属性名与其中一个Car组件id一致,发现注入成功。可知,容器中同一类型组件有多个,是根据 类型+id 同时匹配才注入。只有类型匹配是不够的

1
2
3
4
5
6
7
8
9
10
11
12
@Data
@Component
public class Person {
@Autowired
private Car car; // 与Car的id一致,成功注入Car
@Autowired
private Car carExtend; // 与CarExtend的id一致,成功注入CarExtend
@Autowired
private Car car1;
@Autowired
private Car car2;
}

如果你不想修改变量名呢?此时可以使用@Autowired+@Qualifier的组合。注意必须两个注解结合使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Data
@Component
public class Person {
@Autowired
@Qualifier("car") // 指定组件id
private Car carAaa;
@Autowired
@Qualifier("carExtend")
private Car carBbb;
@Autowired
@Qualifier("car1")
private Car carCcc;
@Autowired
@Qualifier("car2")
private Car carDdd;
}

@Autowired+@Qualifier写起来太麻烦,所以用@Resource进行简化

1
2
3
4
5
6
7
8
9
10
11
12
@Data
@Component
public class Person {
@Resource(name="car")
private Car carAaa;
@Resource(name="carExtend")
private Car carBbb;
@Resource(name="car1")
private Car carCcc;
@Resource(name="car2")
private Car carDdd;
}

3. @Autowired的required属性

将Car的组件注解去掉

1
2
3
4
5
6
@Data
// @Component 去掉
public class Car {
private String name;
private Double price;
}

因为没有类型为Car的组件,所以Person在注入Car时会出错。这是因为@Autowired有一个required属性,默认为true,表示找不到要注入的组件就会出错

1
2
3
4
5
6
@Data
@Component
public class Person {
@Autowired // NoSuchBeanDefinitionException,找不到类型为Car的组件
private Car car;
}

设置required=false

1
2
3
4
5
6
@Data
@Component
public class Person {
@Autowired(required=false) // 找不到类型为Car的组件,但不会出错,只是car的值为null
private Car car;
}

4. @Autowired与@Resource的区别

除了@Autowired,也可以直接用@Resource,二者效果上是等同的

1
2
3
4
5
6
@Data
@Component
public class Person {
@Resource // 也可以直接用@Resource实现自动装配
private Car car;
}

在指定id时,@Autowired要结合@Qualifier,@Resource直接指定name属性即可

1
2
3
4
5
6
@Resource(name="car")
private Car car;

@Autowired
@Qualifier("car")
private Car car;

有3个注解都是实现自动装配的

  • @Resource属于包javax.annotation,是JavaEE注解,所以最通用,扩展性最好,Spring/EJB都可以使用
  • @Autowired属于包org.springframework.beans.factory.annotation,是Spring注解,功能最强大
  • @Inject是EJB注解
panchaoxin wechat
关注我的公众号
支持一下