介绍
@Resource和@Autowired都是做bean的注入时使用,但其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。
Spring不但支持自己定义的@Autowired注解,还支持由JSR-250规范定义的几个注解。如:@Resource、@PostConstruct 及 @PreDestroy
二者联系
- @Autowired和@Resource注解都是作为bean对象注入的时候使用的
- 两者都可以声明在字段和setter方法上
示例:
public class TestServiceImpl {
// 下面两种@Autowired只要使用一种即可
@Autowired
private UserDao userDao; // 用于字段上
@Autowired
public void setUserDao(UserDao userDao) { // 用于属性的方法上
this.userDao = userDao;
}
}
注意:如果声明在字段上,那么就不需要再写setter方法。但是本质上,该对象还是作为set方法的实参,通过执行set方法注入,只是省略了setter方法罢了
二者区别
- @Autowired注解是Spring提供的,而@Resource注解是J2EE本身提供的
- @Autowird注解默认通过byType方式注入,而@Resource注解默认通过byName方式注入
- @Autowired注解注入的对象需要在IOC容器中存在,否则,需要加上属性 required=false,表示忽略当前要注入的bean,如果有直接注入,没有则跳过,不会报错
Spring中的byName与byType
简单介绍一下Spring中的byName与byType
byName就是变量名去匹配bean的id属性,而byType则是变量类型去匹配bean的class属性
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
@Autowired
private UserDao userDao;
此处byName就是拿变量名 userDao 去匹配IOC容器中 id 为 userDao 的Bean;而byType就是拿变量类型 UserDao 去匹配IOC容器中 class 为 com.itheima.dao.impl.UserDaoImpl,因为UserDaoImpl是UserDao实现类,所以是匹配成功
@Autowird注解的使用
@Autowired实现:
注解驱动配置会向spring容器中注册AutowiredAnnotationBeanPostProcessor
当 Spring 容器启动时,AutowiredAnnotationBeanPostProcessor 将扫描 Spring 容器中所有 Bean,当发现 Bean 中拥有 @Autowired 注释时就找到和其匹配(默认按类型匹配)的 Bean,并注入到对应的地方中去。
步骤:@Autowird默认的注入方式为byType,也就是根据类型匹配,当有多个实现类时,则通过byName注入加以区分,或者可以通过配合@Qualifier注解来显式指定name值,指明要使用哪个具体的实现类
例子:
首先有一个接口 UserDao 和两个实现类 UserDaoImpl 和 UserDaoImpl2 ,并且这两个实现类已经加入到Spring的IOC容器中了,代码如下:
如果此时,我们的 service 层如下写法,代码会报错的,
原因:首先通过byType注入,结果发现 UserDao 类型有两个实现类,无法确定具体是哪一个,于是通过byName方式注入,@Autowired的byName注入方式的默认Bean就是类型后面的变量名,这里的变量名为 userDao,IOC容器中的Bean名称为userDao2 和 userDaoImpl2,所以匹配不到,于是报错。
解决方案:
方法一:
修改变量名,改为容器中存在的变量名
方法二:
配合@Qualifier注解来显式指定name值
@Resource注解的使用
@Resource 是JDK1.6支持的注解,由J2EE提供,需要导入包javax.annotation.Resource。默认按照名称进行装配,名称可以通过name属性进行指定。也提供按照byType 注入。
@Resource有两个重要的属性:name 和 type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。
@Resource(name = "userDaoImpl2",type = UserDaoImpl.class)
private UserDao userDao;
如果没有指定name属性,当注解写在字段上时,默认取字段名,按照名称查找。
当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。
当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
示例:
public class TestServiceImpl {
// 下面两种@Resource只要使用一种即可
@Resource(name="userDao")
private UserDao userDao; // 用于字段上
@Resource(name="userDao")
public void setUserDao(UserDao userDao) { // 用于属性的setter方法上
this.userDao = userDao;
}
}
@Resource装配顺序:
①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
③如果指定了type,则从上下文中查找类型匹配的bean进行装配,找不到或是找到多个,都会抛出异常。
④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配,默认以变量名为Bean的id
总结
如果@Requied或者@Autowired写了set方法之上,则程序会走到set方法内部。但如果写在了field之上,则不会进入set方法当中。
@Autowire + @qualifier("") = @Resource(name="")