依赖注入优化
问题起因
在IDEA中,当我们使用@Autowired的时候,会提示不建议使用字段注入。
有哪些注入方式(三种)
1. 字段注入
开发较为常用的就是字段注入。
@Autowired
private UserService userService;
2. set方法注入
也用到了@Autowired注解,但使用方式不同。
字段用在成员变量,set用在成员变量的setter函数上。
private UserService userService;
@Autowired
public void setUserService(UserService userService){
this.userService = userService;
}
3. 构造方法注入(最推荐)
最推荐的一种方式,but这样的流程比较麻烦,后面有简化流程。
private final UserService userService;
public UserController(UserService userService){
this.userService = userService;
}
三种方式对比
总结:
- 构造器注入可靠稳定,只是不灵活,性能差。
- 字段注入和set可靠性和可维护性差。
字段注入缺点
-
基于属性注入的方式, 违背单一职责原则
因为现在的业务一般都会使用很多依赖, 但拥有太多的依赖通常意味着承担更多的责任,而这显然违背了单一职责原则. 并且类和依赖容器强耦合,不能在容器外使用。
-
基于属性注入的方式, 容易导致Spring 初始化失败
因为现在在Spring特别是Spring Boot使用中, 经常会因为初始化的时候, 由于属性在被注入前就引用而导致npe(空指针错误), 进而导致容器初始化失败(类似下面代码块). Java 在初始化一个类时, 是按照 静态变量或静态语句块 –> 实例变量或初始化语句块 –> 构造方法 -> @Autowired 的顺序。 所以在执行这个类的构造方法时,person 对象尚未被注入,它的值还是 null。
-
通过@Autowired 注入, 又因为是 byType 注入, 因此有可能会出现两个相同的类型bean
如下代码快, 就会产生两个相同的Bean, 进而导致Spring 装配失败.
//2. 基于属性注入的方式, 容易导致Spring 初始化失败
@Autowired
private Person person;
private String company;
public UserServiceImpl(){ // 构造方法在person注入之前创建,会初始化失败
this.company = person.getCompany();
}
//3. 通过@Autowired 注入, 又因为是 ByType 注入, 因此有可能会出现两个相同的类型bean
public interface IUser {
void say();
}
@Service
public class User1 implements IUser{
@Override
public void say() {
}
}
@Service
public class User2 implements IUser{
@Override
public void say() {
}
}
@Service
public class UserService {
@Autowired
private IUser user; //在这,可能会出现两个相同类型的Bean
}
解决办法
1. 要用字段注入,可以用@Resource代替
两者作用相当,@Resource支持byName指定名称装配@Resource(name = "userinfo")。
2. 构造注入(十分推荐)
上面已介绍,现在是简化流程,使用Lombok的注解@RequiredArgsConstructor,更方便。
这个注解的意思是必备的构造函数,意思是对一开始就需要初始化的变量做构造,所以需要在需要注入的对象上加final关键字,因为常量在类的创建就要构造。
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
}
PS:@Autowired和@Resource的区别
1. 来源不同
@Autowired是Spring框架的注解,@Resource是Java定义的注解。
2. 依赖查找顺序不同
依赖注入的功能,是通过先在 Spring IoC 容器中查找对象,再将对象注入引入到当前类中。
分为按名称byName和按类型byType。
- @Autowired先byType,再byName。
- @Resource先byName,再byType。
3. 支持参数不同
@Autowired 只支持设置1个 required 的参数,而 @Resource 支持 7 个参数
4. 依赖注入的支持不同
@Autowired 支持属性注入、构造方法注入和 Setter 注入。
@Resource 只支持属性注入和 Setter 注入。
5. 编译器提示不同
注入Mapper时用@Autowired会报错,但是可以运行。
PS OF PS:@Qualifier
使用@Autowired,当容器中存在多个 Bean 的类型与需要注入的相同时,注入将不能执行。
此时要使用byName匹配,就要请出@Qualifier。
private Person p;
@Autowired(required=false)
@Qualifier("ppp") // 如果有好几个Person的实现类,那就通过"ppp"这个名字去匹配类名
public void setPerson(Person p){}
参考&鸣谢
blog.csdn.net/qq_43371556… developer.aliyun.com/article/100…