推荐基于Lombok的Spring注入方式(基于构造器注入)及快速获取Spring容器中管理的对象

本文详细介绍了Spring框架中的三种主要依赖注入方式:构造器注入、setter注入和自动装配(Field注入),并对比了各自的优缺点。同时提供了基于构造器注入的推荐实践,包括利用Lombok简化代码。

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

背景

Java的一大特性是封装,我们经常在实际开发中会封装工具类,甚至是慢慢积累自己的通用工具类,然后用于之后的项目开发。

我们在封装工具类的时候,常常会将工具方法设置为static,方便我们使用类名.方法名快速调用。但有些时候,工具方法封装为static会出现问题,最常见的空指针异常(稍后举例)。所以我们不能那样封装。

如果使用普通方法,正常情况下我们想要去调用的话,就要先实例化类的对象,然后使用对象.方法名去调用方法。这样的话会引发一些问题。

  • 每次都要实例化对象,然后调用,在代码层面上不够简洁
  • 如果方法使用的比较频繁,会实例化很多的对象,影响整个系统的效率

解决上述的问题,我们可能会想到单例模式来解决。手写单例模式是比较麻烦的,Spring的IOC容器管理对象,正是用到了单例模式的思想,可以将我们的对象交由Spring来管理。

源码

出自于我和小伙伴们搭建的开源框架:SMPE-ADMIN
参考地址:https://github.com/shiwei-Ren/smpe-admin/blob/main/smpe-common/src/main/java/marchsoft/utils/SpringContextHolder.java

Spring注入方式对比

Spring Bean 的注入方式一般分为三种:

  1. 构造器注入
  2. Setter注入
  3. 基于注解的 @Autowired 自动装配(Field 注入)

Spring官方推荐使用构造器注入。在IDEA中使用@Autowired注入时会进行提示:

Field injection is not recommended.
Inspection info: Spring Team recommends: “Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies”

自动装配(Field 注入)

使用方法

该种注入方式是使用开发中最常见的注入方式。

@RestController
@RequestMapping("/api/users")
public class UserController {
   
   

	@Autowired
	private IUserService userService;

}

优点

  1. 注入方式简单,只需要使用 @Autowired注解或者 @Resource 注解
  2. 整体代码简洁明了
  3. 新增依赖十分方便,不需要修改原有代码

缺点

  1. 容易出现空指针异常,Field 注入允许构建对象实例的时候依赖的示例对象为空。对于IOC容器以外的环境,除了使用反射来提供它需要的依赖之外,无法复用该实现类。而且将一直是个潜在的隐患,因为你不调用将一直无法发现NullPointException的存在
  2. 对单元测试不友好,如果使用 Field 注入,那么进行单元测试就需要初始化整个Spring 环境,将所有 Bean 实例化
  3. 会出现循环依赖的隐患
public class A {
   
   
    @Autowired
    private B b;
}

public class B {
   
   
    @Autowired
    private A a;
}
  1. 容易破坏单一职责原则

构造器注入

在Spring4.x版本中推荐的注入方式就是这种

The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state.

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

使用方法

@RestController
@RequestMapping("/api/users")
public class UserController {
   
   

	private final IUserService userService;
    private final IDeptService deptService;
    private final IRoleService roleService;
    private final UserCacheClean userCacheClean;

	public UserController(IUserService userService, IDeptServic
### 如何在Spring中实现构造器注入Spring框架中,构造器注入是一种常用的依赖注入方式。通过这种方式,可以确保对象在其生命周期内不可变,并且强制执行所需的依赖项。 #### 构造器注入的基础概念 当类只有一个带参数的构造方法时,Spring自动将其用于依赖注入[^1]。如果存在多个具有相同数量参数的构造函数,则可能会引发构造函数注入类型的歧义问题[^2]。这是因为Spring无法明确区分哪个构造函数应该被调用[^4]。 #### 示例代码展示 下面是一个简单的例子来说明如何使用构造器注入: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class MyService { private final AnotherService anotherService; // 单一构造函数,Spring自动注入 AnotherService 的实例 @Autowired public MyService(AnotherService anotherService) { this.anotherService = anotherService; } public void performAction() { System.out.println("Performing action using " + anotherService); } } ``` 在这个例子中,`MyService` 类有一个带有 `AnotherService` 参数的单一构造函数。由于这是唯一的构造函数,Spring 容器会在创建 `MyService` 实例时自动注入 `AnotherService` 的实例。 #### 多个构造函数的情况处理 如果有多个构造函数,可以通过指定 `@Autowired` 注解以及提供更具体的类型提示来解决潜在的模糊性问题。例如: ```java import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @Component public class ComplexService { private final AnotherService serviceA; private final YetAnotherService serviceB; // 提供两个构造函数并标注其中一个为主构造函数 @Autowired public ComplexService(@Qualifier("serviceA") AnotherService serviceA, YetAnotherService serviceB) { this.serviceA = serviceA; this.serviceB = serviceB; } public void doSomethingComplex() { System.out.println("Using services: " + serviceA + ", " + serviceB); } // 辅助构造函数不会被 Spring 自动选择 public ComplexService(YetAnotherService serviceB) { this(null, serviceB); } } ``` 这里展示了两种不同的构造函数定义情况下的解决方案。主要依靠的是 `@Qualifier` 和其他类似的注解工具帮助消除可能存在的二义性[^3]。 #### 结合Lombok简化开发过程 为了进一步减少样板代码量,可以考虑结合 Lombok 库中的 `@RequiredArgsConstructor` 注解一起使用。这不仅能够自动生成必要的构造函数,还能保持代码简洁明了。 ```java import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor public class SimplifiedService { private final AnotherService anotherService; public void simpleOperation() { System.out.println("Executing operation via dependency injected by constructor."); } } ``` 在这种情况下,无需手动编写任何构造函数声明,因为它们会被 Lombok 自动生成出来。 ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值