@Autowired注解下面的红色波浪线不会影响项目的启动,但是确实idea提示⚠️。首先需要知道依赖注入有三种方式:1、属性注入,2、基于set方法注入,3、构造方法注入。
一、属性注入
@Autowired
UserService userService;
这种注入方式是项目中比较常用(我个人也总用),但是确有着显而易见的缺点:
1、不能实现final对象的注入
不能实现final对象的注入是因为final对象只在两种情况下初始化:第一种是定义的时候就直接初始化,第二种就是在构造函数中初始化;上面的两种情况是针对final修饰的是实例变量而不是类变量,类变量的初始化是在定义的时候初始化或者在静态代码块中初始化的。
2、注入很简单,有不符合单一设计原则的风险
使用基于字段的依赖注入,高频使用的类随着时间的推移,我们会在类中逐渐添加越来越多的依赖项,我们用着很爽,很容易忽略类中的依赖已经太多了。但是如果使用基于构造函数的依赖注入,随着越来越多的依赖项被添加到类中,构造函数会变得越来越大,我们一眼就可以察觉到哪里不对劲。
有一个有超过10个参数的构造函数是一个明显的信号,表明类已经转变一个大而全的功能合集,需要将类分割成更小、更容易维护的块。因此,尽管属性注入并不是破坏单一责任原则的直接原因,但它隐藏了信号,使我们很容易忽略这些信号
3、只能在IoC容器中使用
只能在IoC容器中使用,高度依赖Spring容器,如果换了其他容器,比如:Jfinal等框架,则运行不了。
4、可能会出现空指针异常
@Autowired
private User user;
private String company;
public UserDaoImpl(){
this.company = user.getCompany();
}
这段代码运行会报错空指针,是由于user在调用方法的时候是null。Java 在初始化一个类时,是按照静态变量或静态语句块 –> 实例变量或初始化语句块 –> 构造方法 -> @Autowired 的顺序。所以在执行这个类的构造方法时,user对象尚未被注入,它的值还是 null
二、set注入
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
set注入的缺点是不可以注入不可变对象,因为可以set方法是普通的方法可以重复调用。
三、构造方法注入
private DependencyA dependencyA;
private DependencyB dependencyB;//可以去注入final修饰的属性
//@Autowired不是必需的,Spring 4添加了一个新特性。如果类只提供了带参数的构造函数,你不需要为它的内部属性写@Autowired注释,Spring会自动为你注入属性。
@Autowired
public DI(DependencyA dependencyA, DependencyB dependencyB) {
this.dependencyA = dependencyA;
this.dependencyB = dependencyB;
}
这个是spring官方推荐的注入方式,构造方法注入也有其缺点,但相对于上面的两种注入要好很多。
缺点1:当注入过多会影响代码的美观,让代码看起来比较的长。这个缺点不属于功能性的缺点,我们可以通过Lombok简化构造函数注入:
@AllArgsConstructor用于生成包含所有字段构造的构造函数方法。
@NoArgsConstructor用于生成不带参数的构造函数方法。
@RequiredArgsConstructor生成只包含声明为final或非空字段的构造函数方法。
缺点2:可能会产生循环依赖的问题。可以通过合理设计注入属性依赖关系解决,也可以通过@lazy注解解决。(其他的两种注入也会产生这种问题,但是不需要去手动处理)