@Autowired注入、构造器注入、setter注入的使用方式?区别?

本文介绍了Spring框架中的三种依赖注入方式:@Autowired注入、构造器注入和setter注入,并探讨了它们之间的区别及适用场景。重点推荐使用构造器注入,并讨论了循环依赖问题的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

三种注入方式的使用

1、@Autowired注入(不推荐)

spring官方不推荐使用这种方式,同时idea会给我们发出警告:Field injection is not recommended

@RestController
@RequestMapping("/test")
public class TestController {
 
    @Autowired
    private AService aService;
    @Autowired
    private BService bService;
 
}

2.1、构造器注入(推荐)

spring在4.x版本后就推荐使用构造器的方式的来注入fileld

@RestController
@RequestMapping("/test")
public class TestController {
 
    private final AService aService;
    private final BService bService;
 
    // Spring4.3+之后,constructor注入支持非显示注入方式。
    // @Autowired
    public DictController(AService aService,
                          BService bService) {
        this.aService = aService;
        this.aService = aService;
    }
}

2.2、构造器注入-lombok升级版(推荐)

@RequiredArgsConstructor(onConstructor_ = @Autowired)

该注解是Lombok提供的注解 (可以通过该注解使用构造器注入对象,但是对象必须为final的)

@RequiredArgsConstructor(onConstructor=@_(@Autowired))
@RestController
@RequestMapping("/test")
public class TestController {

	private final AService aService;
	private final BService bService;
}

3、setter注入

@RestController
@RequestMapping("/test")
public class TestController {
 
    private final AService aService;
    private final BService bService;
 
    @Autowired
    public void setAService(AService aService){
        this.aService = aService;
    }
  
    @Autowired
    public void setBService(BService bService){
        this.bService = bService;
    }
}

循环依赖问题如何解决?

前言:
处理循环依赖有很多种方式。我们在处理循环依赖时,首先应该考虑的是是否能够通过重新设计依赖来避免循环依赖并且我们能否接受因重新设计导致的时间成本。如果成本很高或者我们确实需要循环依赖,那么可以使用下面的方式来解决循环依赖问题,推荐优先考虑使用setter方式。

1、使用@Autowired或setter注入。(都支持循环依赖)

2、构造器注入:通过懒加载注解 @Lazy 来支持循环依赖,看下面代码:

@RestController
@RequestMapping("/test")
public class TestController {
 
    private final AService aService;
    private final BService bService;
 
    // Spring4.3+之后,constructor注入支持非显示注入方式。
    // @Autowired
 
    // @Lazy 注解标注在参数上、构造函数上、字段上都是可以的
    public DictController(@Lazy AService aService,
                          @Lazy BService bService) {
        this.aService = aService;
        this.aService = aService;
    }
}
 
or
 
@RequiredArgsConstructor(onConstructor_ = {@Lazy, @Autowired})
@RestController
@RequestMapping("/test")
public class TestController {
 
    private final AService aService;
    private final BService bService;
}

注入方式的区别

@Autowired注入

在容器启动,为对象赋值的时候,遇到@Autowired注解,会用后置处理器机制,来创建属性的实例,然后再利用反射机制,将实例化好的属性,赋值给对象。

构造器注入

使用构造器能避免注入的依赖是空的情况。因为在bean的生命周期里面先执行的是bean的构造器,然后才给bean里面的属性赋值。
(一个对象所有依赖的对象先实例化后,才实例化这个对象。没有他们就没有我原则)

setter注入

使用set方法依赖注入时,Spring首先实例化对象,然后才实例化所有依赖的对象。


虽然在理论上“构造函数注入”和“set方法注入”代表两种不同的依赖强度,但是在spring中,spring并不会把无效的合作者传递给一个bean。如果合作者无效或不存在spring会抛出异常,这样spring保证一个对象的合作者都是可用的。所以在spring中,“构造函数注入”和“set方法注入”唯一的区别在于2种方式创建合作者的顺序不同。


官方推荐理由

单一职责: 当使用构造函数注入的时候,你会很容易发现参数是否过多,这个时候需要考虑你这个类的职责是否过大,考虑拆分的问题;而当使用@Autowired注入field的时候,不容易发现问题

依赖不可变: 只有使用构造函数注入才能注入final

依赖隐藏:使用依赖注入容器意味着类不再对依赖对象负责,获取依赖对象的职责就从类抽离出来,IOC容器会帮你自动装备。这意味着它应该使用更明确清晰的公用接口方法或者构造器,这种方式就能很清晰的知道类需要什么和到底是使用setter还是构造器

降低容器耦合度: 依赖注入框架的核心思想之一是托管类不应依赖于所使用的DI容器。换句话说,它应该只是一个普通的POJO,只要您将其传递给所有必需的依赖项,就可以独立地实例化。这样,您可以在单元测试中实例化它,而无需启动IOC容器并单独进行测试(使用一个可以进行集成测试的容器)。如果没有容器耦合,则可以将该类用作托管或非托管类,甚至可以切换到新的DI框架。

————————————————

### @Autowired 注解与构造器注入区别Spring 框架中,依赖注入可以通过多种方式进行配置,其中 `@Autowired` 注解构造器注入是最常见的两种方式。 #### 使用场景差异 对于 `@Autowired` 注解而言,通常用于字段、setter 方法以及构造函数参数上的自动装配。这种方式简单直观,在早期版本的 Spring 中被广泛采用[^1]。然而,随着框架的发展,官方更倾向于推荐使用构造器注入来处理对象间的依赖关系[^2]。 #### 构造器注入的优势 当应用构造器注入时,所有的必需组件都作为参数传递给类的构造方法,并立即初始化实例变量。这不仅使得 Bean 的创建过程更加清晰明了,而且有助于编写单元测试代码,因为可以在测试环境中轻松替换掉实际的服务实现[^3]。 ```java @RestController @RequestMapping("/test") public class TestController { private final AService aService; private final BService bService; // 显式声明依赖关系,便于理解维护 public TestController(AService aService, BService bService) { this.aService = aService; this.bService = bService; } } ``` 此外,利用 Lombok 库中的 `@RequiredArgsConstructor` 可进一步简化语法糖,自动生成带有 `@Autowired` 的构造函数: ```java import lombok.RequiredArgsConstructor; @RestController @RequestMapping("/test") @RequiredArgsConstructor(onConstructor_ = {@Autowired}) public class TestController { private final AService aService; private final BService bService; } ``` #### 性能考量 尽管两者都能有效完成 DI 工作,但在性能方面可能存在细微差别。由于构造器注入会在对象构建初期即完成所有必要的资源分配工作,因此理论上可能会带来更好的启动速度表现;相反地,如果过度依赖于运行期间动态解析并注入服务,则可能增加一定的开销[^4]。 综上所述,虽然 `@Autowired` 提供了一种便捷的方式来定义 bean 之间的关联性,但从长远来看,遵循最佳实践指南——尽可能多地采纳构造器注入模式——可以显著改善应用程序的设计质量灵活性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值