Field injection is not recommended

Field injection is not recommended

在使用spring框架中的依赖注入注解@Autowired的时候,IDEA报了一个警告

被警告的代码如下

@Autowired
private PayLogService payLogService;

警告的内容如下

Field injection is not recommended // 使用变量的以来注入是不推荐的

Spring官方给出解决方案是这样的

Inspection info: Spring Team recommends: "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies".

翻译过来就是==总是在您的bean中使用构造函数建立依赖注入。总是使用断言强制依赖==

我们直接使用Alt + Enter后代码变成了这样

private final PayLogService payLogService;

public PayLogController(PayLogService payLogService) {
     this.payLogService = payLogService;
}

可以看出,令人心烦的大波浪已经没有了

可话又说回来,为什么Spring官方团队推荐我们这样做?

​ 在讨论上面的问题之间,我们先来了解一下Spring中以来注入的方式

Spring中依赖注入的方式有三种:

  • 基于构造函数的依赖注入
  • 基于setter的依赖注入
  • 基于字段的依赖注入

其中基于字段的依赖注入也就是使用==@Autowired==注入依赖的方式是我们最最常用的方式,但是IDEA或者其他静态代码分析工具会给出提示信息,不推荐使用。

基于构造函数的依赖注入

在基于构造函数的依赖注入中,类构造函数被标注为**@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 a MovieFinder
    private MovieFinder movieFinder;

    // a constructor so that the Spring container can inject a MovieFinder
    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // business logic that actually uses the injected MovieFinder is omitted...
}

基于构造函数注入的主要优点是可以将需要注入的字段声明为final, 使得它们会在类实例化期间被初始化,这对于所需的依赖项很方便。

基于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...
}

基于属性的依赖注入

在基于属性的依赖注入中,字段/属性被标注为**@Autowired**。一旦类被实例化,Spring容器将设置这些字段。

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

​ Java变量的初始化顺序:静态变量或静态语句块–>实例变量或初始化语句块–>构造方法–>@Autowired

相比较而言:

**优点:**变量方式注入非常简洁,没有任何多余代码,非常有效的提高了java的简洁性。即使再多几个依赖一样能解决掉这个问题。

**缺点:**不能有效的指明依赖。相信很多人都遇见过一个bug,依赖注入的对象为null,在启动依赖容器时遇到这个问题都是配置的依赖注入少了一个注解什么的,然而这种方式就过于依赖注入容器了,当没有启动整个依赖容器时,这个类就不能运转,在反射时无法提供这个类需要的依赖。
在使用set方式时,这是一种选择注入,可有可无,即使没有注入这个依赖,那么也不会影响整个类的运行。
在使用构造器方式时已经显式注明必须强制注入。通过强制指明依赖注入来保证这个类的运行。

另一个方面:
依赖注入的核心思想之一就是被容器管理的类不应该依赖被容器管理的依赖,换成白话来说就是如果这个类使用了依赖注入的类,那么这个类摆脱了这几个依赖必须也能正常运行。然而使用变量注入的方式是不能保证这点的。
既然使用了依赖注入方式,那么就表明这个类不再对这些依赖负责,这些都由容器管理,那么如何清楚的知道这个类需要哪些依赖呢?它就要使用set方法方式注入或者构造器注入。

总结下:

在类被加载运行的时候就必须给他的依赖就是强制依赖,构造方法型依赖注入就是强制性,你初始化这个类就要给我这个依赖,选择依赖就是它在初始化的时候IOC不会给你注入,直到你使用到这个依赖时它才会把这个依赖给这个类,比如当你调用这个依赖的方法时才会给你把这个依赖给你注入进去,变量注入和set方法注入都是选择依赖

变量方式注入应该尽量避免,使用set方式注入或者构造器注入,这两种方式的选择就要看这个类是强制依赖的话就用构造器方式,选择依赖的话就用set方法注入。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值