谈谈Spring的三种注入方式

一、引言

Spring框架对Java开发的重要性不言而喻,其核心特性就是IOC(Inversion of Control, 控制反转)和AOP(面向切面编程),平时使用最多的就是其中的IOC,我们通过将组件交由Spring的IOC容器管理,将对象的依赖关系由Spring控制,避免硬编码所造成的过度程序耦合。

二、Spring三种注入方式

1、Field注入

@Controller
public class AppleController {
  @Autowired
  // @Resource
  private AppleService appleService;
}

此种注解方式,应用最广泛:
(1). 注入简单,只需在字段上添加@Autowired或@Resource;
(2). 减少大量冗余代码,美观;
(3). 新增Field时不需要过多代码修改;
Spring 注释 @Autowired 和@Resource 的区别

2、构造器或者叫构造函数注入

@Controller
public class AppleController {

  private final AppleService appService;
  private final AppleService appService1;

  @Autowired
  public AppleController (AppleService appService,AppleService  appService1) {
      this.appService= appService;
      this.appService1= appService1;
  }
}

@Controller
public class AppleController {

  private final AppleService appService;
  // 当只有一个参数时可不写@Autowired
  public AppleController (AppleService appService) {
      this.appService= appService;
  }
}

Spring4.x推荐的注入方式即构造函数注入。对比Field注入:
(1). 新增Field修改麻烦
(2). 当Field多余5个时不符合构造方法的基本规范,显得笨重、臃肿;
3、Setter注入

@Controller
public class AppleController {
  
  private AppleService appService;
  
  //使用方式上同,略
  @Autowired
  public void setAppleService(AppleService appService) {
      this.appService= appService;
  }
}

Spring3.x推荐的注入方式,但并没有被广泛应用,当初推荐的理由:
(1). 解决了构造器注入的笨重;
(2). 可以让类在之后重新配置或者重新注入。

三、为什么Spring4.x推荐构造函数注入?

依赖不可变:加入了final来约束修饰Field,这条是很显然的;
依赖不可为空:在实例化的时候会检查构造函数参数是否为空,如果为空(未找到改类型的实例对象)则会抛出异常。
单一职责:当使用构造函数注入时,如果参数过多,你会发现当前类的职责过大,需要进行拆分。而使用Field注入时,你并不会意识到此问题。
更利于单元测试:按照其他两种方式注入,当单元测试时需要初始化整个spring的环境,而采用构造方法注入时,只需要初始化需要的类即可,即可以直接实例化需要的类。
避免IOC容器以外环境调用时潜在的NPE(空指针异常)
避免循环依赖
保证返回客户端(调用)的代码的时候是完全初始化的状态

四、注意

Field注入方式

//承接上面field注入的代码,假如客户端代码使用下面的调用(或者再Junit测试中使用)
//这里只是模拟一下,正常来说我们只会暴露接口给客户端,不会暴露实现。
AppleController appleController = new AppleController ();
appleController.eat(); // -> NullPointerException

如果使用Field注入,缺点显而易见,对于IOC容器以外的环境,除了使用反射来提供它需要的依赖之外,无法复用该实现类。而且将一直是个潜在的隐患,因为你不调用将一直无法发现NPE的存在

还值得一提另外一点是:使用Field注入可能会导致循环依赖,即A里面注入B,B里面又注入A:

public class A {
    @Autowired
    private B b;
}

public class B {
    @Autowired
    private A a;
}

如果使用构造器注入,在spring项目启动的时候,就会抛出:BeanCurrentlyInCreationException:Requested bean is currently in creation: Is there an unresolvable circular reference?从而提醒你避免循环依赖,如果是Field注入的话,启动的时候不会报错,在使用那个bean的时候才会报错

猜你喜欢

转载自blog.csdn.net/jike11231/article/details/107734136