Spring不再推荐使用@Autowired进行依赖注入

https://blog.youkuaiyun.com/hellojava6666/article/details/147977634

https://zhuanlan.zhihu.com/p/25466474643

https://www.cnblogs.com/lcxz8686TL/p/17288504.html

        在之前开发Spring项目的时候,基本都会使用@Autowired 注解来注入各种需要的Bean,尤其是在service中经常会注入各种dao或者mapper,类里面开头部分有很大的空间都是用来定义各种@Autowired 注解引入的Bean对象。

        在最近的看到很多Spring项目,都逐渐地看不到@Autowired 注解的身影,取而代之的是@RequiredArgsConstructor类注解加上final定义的Bean的方式实现依赖注入。而这也是推荐的构造器注入的方式,可以减少繁杂的@Autowired注解标注。

一.Spring的三种注入方式 

分别是——属性注入、setter 注入、构造器注入

  • 构造器注入 :利用构造方法的参数注入依赖

  • Setter注入 :调用Setter的方法注入依赖

  • 字段注入 :在字段上使用@Autowired/Resource注解

1.属性注入

这种方式是最常用的,可以使用 @Autowired 或者是 @Resource 进行注入,需要在每个Bean上都加上注解。

@Component
public class MyComponent {
    @Autowired
    private MyService myService;
}

2.setter注入

@Controller
public class DemoController {
  private DemoService demoService;
   
  @Autowired
  public void setDemoService(DemoService demoService) {
      this.demoService = demoService;
  }
}

3.构造器注入

这也是目前最推荐的注入方式,根据Spring的特性,Spring的构造器注入时不需要添加@Autowired 注解。

@Component
public class RedisIdWorker {

    private StringRedisTemplate stringRedisTemplate;

    public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }
}

二.Lombok的构造器注解

Lombok 提供了如 @RequiredArgsConstructor 或 @AllArgsConstructor 来自动生成构造函数,并使用 Lombok 的 @NonNull 注解来确保字段在构造时被初始化。

  • @NoArgsConstructor‌:生成无参构造函数,适用于JPA实体类等场景。‌‌
  • @AllArgsConstructor‌:生成包含所有字段的构造函数,可能暴露未初始化的非final字段。‌‌
  • @RequiredArgsConstructor: 为类中所有final修饰的字段或带有@NonNull注解的字段生成构造函数。

三.Spring依赖注入的优化写法

前面提到Spring可以通过构造器注入依赖,而Lombok可以自动生成类的构造函数,那么将两者结合就可以实现简洁的依赖注入写法。

@RequiredArgsConstructor类注解会为类中所有final修饰的字段生成构造函数,而Spring就可以使用该构造函数在不使用@Autowird注解的情况下自动注入所有依赖,从而简化代码编写。

典型的场景就是Controller层或Service层需要注入多个Mapper/Service接口时,减少冗余的@Autowired注解。‌‌

@Component
@RequiredArgsConstructor
public class MyComponent {
    private final MyService myService;
    private final MyMapper myMapper; 
}

四.推荐使用构造器注入的原因

在上文中,经过优化后的依赖注入从代码上看更加清晰简洁,当然简化代码只是其中一个原因。

近年来,Spring团队已经将构造函数注入作为处理依赖注入的首选方法,逐渐放弃使用@Autowired进行依赖注入,原因如下:

1.使用@Autowired注入的问题

  • 隐藏的依赖:当@Autowired应用于字段时,依赖项是在幕后注入的,这可能导致隐藏的依赖关系。这种做法使得很难了解一个类需要哪些资源才能正常工作,从而增加了测试和调试的难度。
  • 不便于不可变性:字段注入允许依赖项是可变的,这使得类在以后更容易修改它们。这降低了组件的不可变性,可能导致难以追踪的bug。
  • 测试困难:依赖于字段注入的组件测试起来比较棘手。由于依赖项不是通过构造函数传递的,测试时需要手动模拟或注入这些字段,这会增加不必要的样板代码。

2.构造器注入的优点

  • 强制要求依赖项:构造函数注入要求在创建类实例时提供所有必需的依赖项。这确保了类在创建时始终处于有效状态,所有必要的依赖项都已设置。
  • 不可变性:构造函数注入鼓励使用final字段,这强制执行不可变性。一旦依赖项被注入,它就不能被更改,从而减少了意外修改和代码bug的风险。
  • 提高测试性:使用构造函数注入测试组件更加容易。在测试中,您可以直接将模拟的依赖项传递到构造函数中,而不需要依赖Spring的内部自动装配。
### Spring推荐使用 `@Autowired` 的原因 Spring 官方从版本 4.0 开始不再推荐通过 `@Autowired` 进行字段注入[^1]。主要原因在于这种注入方式存在一些潜在的风险和局限性: #### 1. **测试困难** 当依赖项被直接注入到私有字段中时,单元测试会变得更加复杂。由于无法轻松地通过构造函数或 setter 方法替换这些依赖项,开发者通常需要借助反射工具来完成测试工作。 #### 2. **不可变性和线程安全性** 字段注入使得对象的状态可以在运行时被修改,这可能导致意外的行为并破坏不可变性设计原则。相比之下,构造器注入可以通过创建不可变对象提高程序的健壮性[^3]。 #### 3. **与框架解耦** 如果项目未来可能迁移到其他 IoC 容器或者完全移除 Spring,则基于字段注入的方式可能会增加迁移成本。而采用构造器注入能够减少对特定框架 API 的依赖程度[^4]。 --- ### 替代方案及其优势 针对以上提到的问题,Spring 推荐两种更优的选择——**构造器注入** 和 **Setter 注入**,它们各自具备如下特点: #### 构造器注入 - 可以确保所有必需的依赖都已提供给组件,从而避免 NullPointerException (NPE)[^2]. - 支持定义 final 类型成员变量,有助于构建更加安全可靠的软件架构. 下面是一个简单的例子展示如何实现构造器注入: ```java public class MyService { private final Dependency dependency; public MyService(Dependency dependency) { // 使用构造方法传参初始化 this.dependency = Objects.requireNonNull(dependency); } public void execute() { dependency.performAction(); } } ``` #### Setter 注入 虽然不如前者流行,但在某些场景下仍然适用(比如部分属性是非强制性的).其主要优点是可以保持向后兼容的同时允许动态更新配置. 示例代码如下所示: ```java public class AnotherService { private OptionalDependency optionalDependency; public void setOptionalDependency(OptionalDependency dep){ this.optionalDependency=dep; } ... } ``` 综上所述,在实际应用当中应优先考虑利用构造器来进行必要的DI操作;而对于那些非核心功能则可以选择适当运用setter方式进行补充调整. ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值