所有分类
  • 所有分类
  • 未分类

Spring–注入的方式–方法/实例

简介

说明

本文用实例介绍SpringBoot如何装配bean。

用法介绍

下边@Autowired基本可以用于@Value。但有一点要注意:@Value用于参数时,@Value不能省略,例如:

String name;
public abc(@Value(${"myName"}String myName) {
  this.name = myName;
}

方式1:field注入

示例

@Controller
public class FooController {
  @Autowired
  private FooService fooService;
  
  //简单的使用例子,下同
  public List<Foo> listFoo() {
      return fooService.list();
  }
}

优点

  1. 代码少,简洁明了。
  2. 新增依赖十分方便,不需要修改原有代码

缺点

  1. 容易出现空指针异常。Field 注入允许构建对象实例时依赖的对象为空,导致空指针异常不能在启动时就爆出来,只能在用到它时才发现。
    空指针异常不是必现的,与bean的实例化顺序有关。有时,把依赖的bean改个名字就会报空指针异常。
  2. 会出现循环依赖的隐患。

方式2:构造器注入

示例

@Controller
public class FooController {
  
  private final FooService fooService;
  
  // @Autowired不写也可以
  @Autowired
  public FooController(FooService fooService) {
      this.fooService = fooService;
  }
}

优点

  1. 保证注入的组件不可变
  2. 确保需要的依赖不为空
  3. 解决循环依赖的问题

能够保证注入的组件不可变,并且确保需要的依赖不为空。此外,构造器注入的依赖总是能够在返回客户端(组件)代码的时候保证完全初始化的状态。 

  • 依赖不可变(immutable objects)。
    即:final关键字。
  • 依赖不可为空(required dependencies are not null)。省去了我们对其检查。
        当要实例化FooController时,由于自己实现了有参数的构造函数,所以不会调用默认构造函数,那么就需要Spring容器传入所需要的参数,所以就两种情况:
        1、有该类型的参数=> 传入,OK 。2:无该类型的参数=> 报错。所以保证不会为空 )
  • 完全初始化的状态(fully initialized state)。跟上面的依赖不可为空结合起来。
        向构造器传参前,为确保注入的内容不为空,要调用依赖组件的构造方法完成实例化。而在Java类加载实例化的过程中,构造方法是最后一步(之前如果有父类先初始化父类,然后自己的成员变量,最后才是构造方法,这里不详细展开。)。所以返回来的都是初始化之后的状态。
  • 解决循环依赖(spring 的三层缓存机制)

官方文档

The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.

缺点

  • 当注入参数较多时,代码臃肿。

方式3:setter注入

@Controller
public class FooController {
  
  private FooService fooService;
  
  @Autowired
  public void setFooService(FooService fooService) {
      this.fooService = fooService;
  }
}

优点

  1. 注入参数多的时候比较方便。构造器注入参数太多了,显得很笨重
  2. 能让类在之后重新配置或者重新注入。 

官方文档:

The Spring team generally advocates setter injection, because large numbers of constructor arguments can get unwieldy, especially when properties are optional. Setter methods also make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is a compelling use case.

Some purists favor constructor-based injection. Supplying all object dependencies means that the object is always returned to client (calling) code in a totally initialized state. The disadvantage is that the object becomes less amenable to reconfiguration and re-injection.

缺点

 有一定风险。set注入是后初始化其依赖对象,如果一个对象在没有完全初始化就被外界使用是不安全的(尤其是在多线程场景下更加突出)。 ​

0

评论0

请先

显示验证码
没有账号?注册  忘记密码?

社交账号快速登录