我们在使用IDEA编码时,如果用到了
@Autowired
注解注入bean,会发现IDEA会给代码标个波连线,鼠标移动上去,会发下idea提示:不推荐使用Filed injection
,这是Spring的核心DI(Dendency Injection)
,即依赖注入。 今天我们就来聊聊,为什么IDEA不推荐使用Filed injection
我们先来温习一下Spring的DI注入
DI注入的三种方式及对比
属性注入
属性注入应该是我们用的最多的一种,即通过@Autowired
注解,该注解默认是按照ByType
方式(按类型)注入Bean,默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false)
。示例代码:
@Service
public class UserService {
private static User user;
// 1. Filed Injection 属性注入
@Autowired
private PlayService playService;
}
setter 方法注入
setter方式也会用到@Autowired
注解,不过是用在成员属性的set
方法上,这个方式维护起来,就感觉很麻烦。
// 2. Setter Injection setter注入
private PlayService playService;
@Autowired
public void setPlayService(PlayService playService) {
this.playService = playService;
}
构造器注入
构造器注入,则是把需要注入的对象,通过构造器来进行初始化
private PlayService playService;
UserService(PlayService playService) {
this.playService = playService;
}
三种方式的优劣对比
各个方面对比结果:
同时,使用属性注入,即使用Autowired
,还可能会有以下几个问题:
@Autowired
是Spring框架自带的注解,如果不使用Sping IOC这一套,这个注入就失效了,拓展性和复用性比较差- 当注入的是接口,且接口有多个实现时,这个注入就会导致程序启动不了,需要额外的注解辅助才行,如@Qulifield.
如以下代码:
@Component
public interface PlayService {
void play();
}
@Component
@Slf4j
public class Mp3Player implements PlayService {
@Override
public void play() {
log.info("Mp3Player play()");
}
}
@Component
@Slf4j
public class Mp4Player implements PlayService {
@Override
public void play() {
log.info("Mp4Player play()");
}
}
PlayService接口有两个实现类,此时在其他类中注入该Bean, 由于@Autowired
注解是按照ByType类型注入,此时会找到两个Bean, 但不知道到底该使用哪个,所以会报错
@Autowired
private PlayService playService;
报错信息如:UserService required a single bean, but 2 were found:...
此时就需要使用@Qualifier()
来配合使用才行, 通过该注解,指定具体Bean的名称
@Autowired
@Qualifier("mp4Player")
private PlayService playService;
因此虽然使用@Autowired
是很方便简单,但可能会有问题
不过也有替代方案,就是使用java自带的@Resource
注解, 这个IDEA是不会报警告哦~!
为什么可以使用@Resource,但不推荐使用@Autowired?
来源
@Resource
是Java的标准注解,定义在javax.annotation.Resource
包中,主要用于EJB 组件的依赖注入,但在Spring中也可以用于bean的注入。@Autowired
是 Spring 框架提供的注解,定义在org.springframework.beans.factory.annotation.Autowired
包中,专门用于 Spring 环境下的依赖注入。
默认行为
@Resource
默认按照名称进行注入,如果找不到匹配名称的 bean,则退而求其次按照类型进行注入。可以通过 name 属性指定 bean 名称,或者通过 lookup 属性指定查找方法。@Autowired
默认按照类型进行注入,如果类型匹配的 bean 多于一个,则会抛出异常,除非指定了具体的 bean 名称。可以通过 required 属性来控制是否必须找到匹配的 bean。
IDEA推荐@Resource
@Resource
是 Java 标准的一部分,因此可能被视为更通用的解决方案。- 使用
@Resource
可以避免 Spring 的特定依赖,使得代码看起来与 Spring 解耦。
IDEA 的推荐也可能基于减少 Spring 特定的警告,例如关于字段注入的警告。
总结
- 我个人是比较推荐使用
@Resource
注解,不仅简单,代码整洁,而且容错率也高,关键能去掉IDEA的警告!(主打一个听劝.) - 不推荐使用setter和构造器方式, 代码太繁杂了,不方便维护
最后到底每个人使用哪个注解,还是基于组内的架构或者开发规范,大家统一使用一种方式就行,几个不同的方式其实都没什么大的影响,存在即合理。