在上一节我们使用Autowired进行了bean的装配,@Autowired与@Resource都可以用来装配bean,但它们之前还是有一些区别,它们的区别具体体现为以下几点:
- 来源不同
- 对Constructor注入的支持不同
- 查找顺序不同
- 支持参数不同
1. 来源不同
@Resource
位于包javax.annotation
,是JDK原生的注解;
而@Autowired
位于包org.springframework.beans.factory.annotation
,是Spring2.5 之后引入的注解。
2. 对Constructor注入的支持不同
由于构造方法在对象创建的时候调用,执行的时期较早,由于jdk将@Resource的执行时期设计晚于构造方法调用的时期,因此在构造方法上使用@Resource注解编译器会报错:
3. 查找顺序不同
3.1 Bean在Spring中的存储方式
Bean在Spring中的存储方式是类似于Java中的HashMap
的。
一个Bean对象有它的Name
和Type
,分别对应着xml文件中配置的Bean的id
和class
也就是说通过同一个类可以创建两个id
不同的Bean对象:
<bean id="user1" class="UserBean"></bean>
<bean id="user2" class="UserBean"></bean>
通过Java的数据结构HashMap<key, value>
,我们可以通过key(键)
找到对应的value(值)
,而Bean的Name+Type,就对应着key,而Bean对象就对应着value
3.2 @Autowired查找顺序
下面的代码中,DemoDao
对应着Type, demoDao
对应着Name:
@Autowired
private DemoDao demoDao;
@Autowired是先通过Type查找,如果一个Type对应多个Bean,它才会去通过Name查找,如果找不到唯一的Name,那么就会抛出异常。
实验验证:
第一次,只有DemoDaoImpl
实现DemoDao
接口,UserService
的代码如下,只有Bean的Type能匹配上,而Name无法匹配上:
@Service
public class UserService {
@Autowired
private DemoDao demoDao;
public void doService() {
demoDao.selectAll();
System.out.println("Do User Service");
}
}
成功找到Bean并运行:
select * from demo
Do User Service
Do User Controller.
第二次,我让DemoDaoImpl
和UserDaoImpl
都实现DemoDao接口:
@Repository
public class DemoDaoImpl implements DemoDao {
@Override
public void selectAll() {
System.out.println("select * from demo");
}
}
@Repository
public class UserDaoImpl implements DemoDao {
@Override
public void selectAll() {
System.out.println("select * from user");
}
}
运行程序发现报了一个没有唯一定义的Bean的异常:
NoUniqueBeanDefinitionException: No qualifying bean of type 'com.chenshu.dao.DemoDao' available:
第三次,我同样让DemoDaoImpl
和UserDaoImpl
都实现DemoDao
接口,并且让UserService
中的Name与DemoDaoImpl
匹配上:
@Service
public class UserService {
@Autowired
private DemoDao demoDaoImpl;
public void doService() {
demoDaoImpl.selectAll();
System.out.println("Do User Service");
}
}
这次又能正常注入Bean,并成功调用Bean的方法:
select * from demo
Do User Service
Do User Controller.
上面的结论足以验证@Autowired的查找顺序是先通过Type查找再通过Name查找。
3.3 @Resource查找顺序
这里我直接给出结论:@Resource 是先根据名称查找,如果(根据名称)查找不到,再根据类型进行查找。
4. 支持参数不同
点开@Resource注解并查看它的Structure:
点开@Autowired注解并查看它的Structure:
对比二者,@Resource
注解提供了更丰富的参数
4.1 引入需求
UserService代码如下:
@Service
public class UserService {
@Autowired
private DemoDao demoDao;
public void doService() {
demoDao.selectAll();
System.out.println("Do User Service");
}
}
此时有UserDaoImpl
和DemoDaoImpl
实现DemoDao
接口,现在我想在不改变参数名的情况下,解决一个类对应两个Bean对象的问题
4.2 解决方案
方案一:通过@Resource
注解
@Resource
注解提供了一个name参数,通过该参数可以指定通过该参数的值来查找Bean:
@Service
public class UserService {
@Resource(name = "userDaoImpl")
private DemoDao demoDao;
public void doService() {
demoDao.selectAll();
System.out.println("Do User Service");
}
}
方案二:通过@Autowired
注解
虽说@Resource
能够通过参数便利地解决问题,但它还是有个硬伤:无法实现构造器注入。
@Autowired
没有提供相应的参数实现该需求,但是我们可以通过额外的@Qualifier
注解来实现:
@Service
public class UserService {
@Autowired
@Qualifier(value = "userDaoImpl")
private DemoDao demoDao;
public void doService() {
demoDao.selectAll();
System.out.println("Do User Service");
}
}
```在上一节我们使用Autowired进行了bean的装配,@Autowired与@Resource都可以用来装配bean,但它们之前还是有一些区别,它们的区别具体体现为以下几点:
- 来源不同
- 对Constructor注入的支持不同
- 查找顺序不同
- 支持参数不同
# 1. 来源不同
`@Resource`位于包`javax.annotation`,是JDK原生的注解;
而`@Autowired`位于包`org.springframework.beans.factory.annotation`
,是Spring2.5 之后引入的注解。
# 2. 对Constructor注入的支持不同
由于构造方法在对象创建的时候调用,执行的时期较早,由于jdk将@Resource的执行时期设计晚于构造方法调用的时期,因此在构造方法上使用@Resource注解编译器会报错:
![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a2c31913d1d74067862b301fca4dbd44~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=382&h=87&s=11624&e=png&b=1c1c1f)
# 3. 查找顺序不同
## 3.1 Bean在Spring中的存储方式
Bean在Spring中的存储方式是类似于Java中的`HashMap`的。
一个Bean对象有它的`Name`和`Type`,分别对应着xml文件中配置的Bean的`id`和`class`
也就是说通过同一个类可以创建两个`id`不同的Bean对象:
```xml
<bean id="user1" class="UserBean"></bean>
<bean id="user2" class="UserBean"></bean>
通过Java的数据结构HashMap<key, value>
,我们可以通过key(键)
找到对应的value(值)
,而Bean的Name+Type,就对应着key,而Bean对象就对应着value
3.2 @Autowired查找顺序
下面的代码中,DemoDao
对应着Type, demoDao
对应着Name:
@Autowired
private DemoDao demoDao;
@Autowired是先通过Type查找,如果一个Type对应多个Bean,它才会去通过Name查找,如果找不到唯一的Name,那么就会抛出异常。
实验验证:
第一次,只有DemoDaoImpl
实现DemoDao
接口,UserService
的代码如下,只有Bean的Type能匹配上,而Name无法匹配上:
@Service
public class UserService {
@Autowired
private DemoDao demoDao;
public void doService() {
demoDao.selectAll();
System.out.println("Do User Service");
}
}
成功找到Bean并运行:
select * from demo
Do User Service
Do User Controller.
第二次,我让DemoDaoImpl
和UserDaoImpl
都实现DemoDao接口:
@Repository
public class DemoDaoImpl implements DemoDao {
@Override
public void selectAll() {
System.out.println("select * from demo");
}
}
@Repository
public class UserDaoImpl implements DemoDao {
@Override
public void selectAll() {
System.out.println("select * from user");
}
}
运行程序发现报了一个没有唯一定义的Bean的异常:
NoUniqueBeanDefinitionException: No qualifying bean of type 'com.chenshu.dao.DemoDao' available:
第三次,我同样让DemoDaoImpl
和UserDaoImpl
都实现DemoDao
接口,并且让UserService
中的Name与DemoDaoImpl
匹配上:
@Service
public class UserService {
@Autowired
private DemoDao demoDaoImpl;
public void doService() {
demoDaoImpl.selectAll();
System.out.println("Do User Service");
}
}
这次又能正常注入Bean,并成功调用Bean的方法:
select * from demo
Do User Service
Do User Controller.
上面的结论足以验证@Autowired的查找顺序是先通过Type查找再通过Name查找。
3.3 @Resource查找顺序
这里我直接给出结论:@Resource 是先根据名称查找,如果(根据名称)查找不到,再根据类型进行查找。
4. 支持参数不同
点开@Resource注解并查看它的Structure:
点开@Autowired注解并查看它的Structure:
对比二者,@Resource
注解提供了更丰富的参数
4.1 引入需求
UserService代码如下:
@Service
public class UserService {
@Autowired
private DemoDao demoDao;
public void doService() {
demoDao.selectAll();
System.out.println("Do User Service");
}
}
此时有UserDaoImpl
和DemoDaoImpl
实现DemoDao
接口,现在我想在不改变参数名的情况下,解决一个类对应两个Bean对象的问题
4.2 解决方案
方案一:通过@Resource
注解
@Resource
注解提供了一个name参数,通过该参数可以指定通过该参数的值来查找Bean:
@Service
public class UserService {
@Resource(name = "userDaoImpl")
private DemoDao demoDao;
public void doService() {
demoDao.selectAll();
System.out.println("Do User Service");
}
}
方案二:通过@Autowired
注解
虽说@Resource
能够通过参数便利地解决问题,但它还是有个硬伤:无法实现构造器注入。
@Autowired
没有提供相应的参数实现该需求,但是我们可以通过额外的@Qualifier
注解来实现:
@Service
public class UserService {
@Autowired
@Qualifier(value = "userDaoImpl")
private DemoDao demoDao;
public void doService() {
demoDao.selectAll();
System.out.println("Do User Service");
}
}