Java中@Resource 和 @Autowired 的区别
@Resource
@Resource是Java自己的注解
先来看一下源码:
@Resource有两个属性是比较重要的,分别是name和type;Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。默认按name进行注入。
下面看一下这样的一个变量注入方式:
按type进行注入的自动注入策略,这个type指的就是类的类型,可以这样理解,比如Apple.class,类型就是Apple,Person.class,类型就是Person。
如果我有两个Person类,这个时候就无法辨别注入对象,就可以使用name属性去辨别。
在spring中, 被@Component标识的类会在servlet容器启动时加载单实例(默认设置下),用@Resource注解可以注入,如果需要的bean没有被提前加载, 则会报错。
在加载的时,是根据类名(不包括package地址)判断,出现重复的类名会报异常(不在同一个package, 也会报异常)。如果类名相同,可以标识成不同的bean,然后@Resource的name去辨别。
假设,有两个相同的实现类,那么可以用name去辨别,如下:
@Service("a")
public class ReportServiceImpl implements ReportService{
......
}
@Service("b")
public class ReportServiceImpl implements ReportService{
......
}
注入的时候指定名称为a的那个实现类:
这样指定,就知道是哪一个了。
@AutoWired
@AutoWired是spring的注解,Autowired只根据type进行注入,不会去匹配name。如果涉及到type无法辨别注入对象时,那需要依赖@Qualifier或@Primary注解一起来修饰。@Resource默认按名称方式进行bean匹配,@Autowired默认按类型方式进行bean匹配。
使用@AutoWired变量注解方式时,会有黄色波浪线,idea会提示:
Spring团队建议:“在bean中始终使用基于构造函数的依赖注入。始终对强制依赖项使用断言”。
意思是说,用@AutoWired的注入时,尽量用基于构造函数的依赖注入,而不是变量的方式注入。
这就是构造函数方式的依赖注入:
再来看一下@AutoWired注解的源码:
只有required属性,没有其他属性了,根据type进行注入。
用@AutoWired的变量注入时,如果碰到无法分辨的对象,就无法注入成功。但是可以结合@Qualifier注解使用,表明哪个实现类才是我们需要的。
但是仍然不建议使用变量注入方式。
1、可能会造成NPE,如下:
public class TestController {
@Autowired
private TestService testService;
private String name;
public TestController(){
this.name= testService.getName();
}
}
这段代码执行时会报NPE。Java类会先执行构造函数,然后在通过@Autowired注入实例,二构造函数里面需要注入的对象,因此在执行构造函数的时候就会报错。
2、还可能回导致循环依赖,即A里面注入B,B里面又注入A。
注:在代码中发现构造方法中注入了很多依赖,显得很臃肿,对于这个问题,说明类中有太多的责任,违反了类的单一性职责原则,这时候需要考虑使用单一职责原则进行代码重构。
总结
简单来说,这两的区别就是:
- @Resource:java的注解,属性较多,type无法分辨时可以用name分辨
- @Autowired:spring的注解,一个属性,type无法分辨时需要借助@Qualifier注解才能使用,使用@Autowired方式最好使用构造函数的方式注入。