前语

Spring 官方已不引荐运用 Autowired 字段/特点注入 bean,一些大公司的新项目也明令禁止运用了。

说明

最近公司晋级结构,由本来的 spring framework 3.0 晋级到 5.0,然后写代码的时候忽然发现 idea 在特点注入的 @Autowired 注解上给出警告提示,就像下面这样的,也是挺懵逼的,毕竟这么写也很多年了。

Field injection is not recommended

公司为什么禁止在SpringBoot项目中使用@Autowired注解

查阅了相关文档了解了一下,本来这个提示是 spring framework 4.0 以后开端出现的,spring 4.0 开端就不引荐运用特点注入,改为引荐结构器注入和 setter 注入。

下面将展现了 spring 结构能够运用的不同类型的依靠注入,以及每种依靠注入的适用状况。

依靠注入的类型

虽然针对 spring framework 5.1.3 的文档只界说了两种首要的依靠注入类型,但实际上有三种:

  • 根据结构器的依靠注入
  • 根据 setter 的依靠注入
  • 根据字段的依靠注入

其间根据字段的依靠注入被广泛运用,可是 idea 或许其他静态代码剖析工具会给出提示信息,不引荐运用。

乃至能够在一些 Spring 官方攻略中看到这种注入办法:

公司为什么禁止在SpringBoot项目中使用@Autowired注解

2.1 根据结构器的依靠注入

在根据结构函数的依靠注入中,类结构函数被标注为 @Autowired,并包含了许多与要注入的目标相关的参数。

@Component
public class ConstructorBasedInjection {
    private final InjectedBean injectedBean;
    @Autowired    
    public ConstructorBasedInjection(InjectedBean injectedBean) {        
        this.injectedBean = injectedBean;    
    }
}

然后在spring官方文档中,@Autowired 注解也是能够省去的。

public class SimpleMovieLister {
    // the SimpleMovieLister has a dependency on the MovieFinder
    private MovieFinder movieFinder;
    // a setter method so that the Spring container can inject a MovieFinder
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    // business logic that actually uses the injected MovieFinder is omitted...
}

根据结构函数注入的首要优点是能够将需要注入的字段声明为 final, 使得它们会在类实例化期间被初始化,这关于所需的依靠项很便利。

2.2 根据 Setter 的依靠注入

在根据 setter 的依靠注入中,setter 办法被标注为 @Autowired。一旦运用无参数结构函数或无参数静态工厂办法实例化 Bean,为了注入 Bean 的依靠项,Spring 容器将调用这些 setter 办法。

@Component
public class SetterBasedInjection {
    private InjectedBean injectedBean;
    @Autowired
    public void setInjectedBean(InjectedBean injectedBean) {
        this.injectedBean = injectedBean;
    }
}

和根据结构器的依靠注入相同,在官方文档中,根据 Setter 的依靠注入中的 @Autowired 也能够省去。

public class SimpleMovieLister {
    // the SimpleMovieLister has a dependency on the MovieFinder
    private MovieFinder movieFinder;
    // a setter method so that the Spring container can inject a MovieFinder
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    // business logic that actually uses the injected MovieFinder is omitted...
}

2.3 根据特点的依靠注入

在根据特点的依靠注入中,字段/特点被标注为 @Autowired。一旦类被实例化,Spring 容器将设置这些字段。

@Component
public class FieldBasedInjection {
    @Autowired
    private InjectedBean injectedBean;
}

正如所看到的,这是依靠注入最洁净的办法,由于它防止了增加样板代码,而且不需要声明类的结构函数。代码看起来很洁净简练,可是正如代码查看器现已向咱们暗示的那样,这种办法有一些缺点。

根据字段的依靠注入缺点

3.1 不允许声明不可变域

根据字段的依靠注入在声明为 final/immutable 的字段上不起效果,由于这些字段必须在类实例化时实例化。声明不可变依靠项的仅有办法是运用根据结构器的依靠注入。

3.2 简单违背单一责任规划准则

在面向目标的编程中,五大规划准则SOLID被广泛应用,(国内一般为六大规划准则),用以提高代码的重用性,可读性,可靠性和可保护性。

S 在 SOLID 中代表单一责任准则,即一个类应该只担任一项责任,这个类提供的一切服务都应该只为它担任的责任服务。

运用根据字段的依靠注入,高频运用的类跟着时刻的推移,咱们会在类中逐步增加越来越多的依靠项,咱们用着很爽,很简单忽略类中的依靠现已太多了。可是假如运用根据结构函数的依靠注入,跟着越来越多的依靠项被增加到类中,结构函数会变得越来越大,咱们一眼就能够察觉到哪里不对劲。

有一个有超过10个参数的结构函数是一个明显的信号,表明类现已转变一个大而全的功用合集,需要将类分割成更小、更简单保护的块。

因而,虽然特点注入并不是损坏单一责任准则的直接原因,但它隐藏了信号,使咱们很简单忽略这些信号。spring系列技术文章:www.yoodb.com/spring/spri…

3.3 与依靠注入容器严密耦合

运用根据字段的依靠注入的首要原因是为了防止 getter 和 setter 的样板代码或为类创立结构函数。最终,这意味着设置这些字段的仅有办法是经过Spring容器实例化类并运用反射注入它们,否则字段将坚持 null。

依靠注入规划形式将类依靠项的创立与类本身分离开来,并将此责任转移到类注入容器,从而允许程序规划解耦,并遵循单一责任和依靠项倒置准则(相同可靠)。因而,经过自动安装(autowiring)字段来完成的类的解耦,最终会由于再次与类注入容器(在本例中是 Spring)耦合而丢失,从而使类在Spring容器之外变得无用。

这意味着,假如您想在应用程序容器之外运用您的类,例如用于单元测试,您将被迫运用 Spring 容器来实例化您的类,由于没有其他或许的办法(除了反射)来设置自动安装字段。

3.4 隐藏依靠联系

在运用依靠注入时,受影响的类应该运用公共接口清楚地揭露这些依靠项,办法是在结构函数中揭露所需的依靠项,或许运用办法(setter)揭露可选的依靠项。当运用根据字段的依靠注入时,实质上是将这些依靠对外隐藏了。

总结

咱们现已看到,根据字段的注入应该尽或许地防止,由于它有许多缺点,无论它看起来多么高雅。引荐的办法是运用根据结构函数和根据setter的依靠注入。关于必需的依靠,主张运用根据结构函数的注入,设置它们为不可变的,并防止它们为 null。关于可选的依靠项,主张运用根据 setter 的注入。

参阅文档

Field injection is not recommended – Spring IOCbyMarc Nuri

spring官方文档 1.4. Dependencies