当前位置: 首页 > news >正文

Spring为什么推荐使用构造函数进行依赖注入??

Spring 推荐使用构造函数进行依赖注入,这是基于多年的实践和经验总结。

1. 不可变性(Immutability)

核心优势:对象状态不可变

// 构造函数注入 - 不可变
@Service
public class UserService {private final UserRepository userRepository;private final EmailService emailService;// 依赖在构造时确定,后续不可更改public UserService(UserRepository userRepository, EmailService emailService) {this.userRepository = userRepository;this.emailService = emailService;}
}// Setter注入 - 可变(存在风险)
@Service
public class UserService {private UserRepository userRepository;private EmailService emailService;@Autowiredpublic void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository; // 可能被重复设置}
}

2. 依赖完整性保证

在对象创建时确保所有依赖就绪

// 构造函数注入:编译时就能发现缺失的依赖
@Service
public class OrderService {private final PaymentService paymentService;private final InventoryService inventoryService;// 如果Spring找不到PaymentService bean,启动就会失败public OrderService(PaymentService paymentService, InventoryService inventoryService) {this.paymentService = paymentService;this.inventoryService = inventoryService;}public void createOrder(Order order) {// 使用时不需要检查依赖是否为nullpaymentService.processPayment(order); // 安全调用}
}// 对比:Setter注入可能产生NPE
@Service
public class OrderService {private PaymentService paymentService;@Autowiredpublic void setPaymentService(PaymentService paymentService) {this.paymentService = paymentService;}public void createOrder(Order order) {// 可能忘记调用setter,导致NPEpaymentService.processPayment(order); // 潜在NPE风险}
}

3. 更好的测试体验

构造函数注入便于单元测试

// 使用构造函数注入 - 测试简单
@Service
public class UserService {private final UserRepository userRepository;public UserService(UserRepository userRepository) {this.userRepository = userRepository;}public User findUser(Long id) {return userRepository.findById(id);}
}// 测试代码
class UserServiceTest {@Testvoid testFindUser() {// 可以直接new,不需要Mockito注解UserRepository mockRepo = Mockito.mock(UserRepository.class);UserService userService = new UserService(mockRepo); // 简单明了// 测试逻辑...}
}// Setter注入测试相对繁琐
@Service
public class UserService {private UserRepository userRepository;@Autowiredpublic void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}
}class UserServiceTest {@Testvoid testFindUser() {UserService userService = new UserService(); // 先创建空对象UserRepository mockRepo = Mockito.mock(UserRepository.class);userService.setUserRepository(mockRepo); // 再设置依赖// 更复杂的设置过程}
}

4. 循环依赖检测

构造函数注入能早期发现循环依赖

// 循环依赖示例
@Service
public class ServiceA {private final ServiceB serviceB;public ServiceA(ServiceB serviceB) {  // Spring启动时会检测到循环依赖this.serviceB = serviceB;}
}@Service
public class ServiceB {private final ServiceA serviceA;public ServiceB(ServiceA serviceA) {  // 启动失败:BeanCurrentlyInCreationExceptionthis.serviceA = serviceA;}
}// 控制台错误信息:
// Error creating bean with name 'serviceA': 
// Requested bean is currently in creation: Is there an unresolvable circular reference?

5. 代码质量提升

5.1 明确的对象创建契约

// 清晰的依赖声明
@Service
public class OrderProcessingService {private final OrderValidator validator;private final PaymentGateway paymentGateway;private final EmailNotifier emailNotifier;private final AuditLogger auditLogger;// 构造函数明确表达了创建该对象需要哪些依赖public OrderProcessingService(OrderValidator validator,PaymentGateway paymentGateway,EmailNotifier emailNotifier,AuditLogger auditLogger) {this.validator = validator;this.paymentGateway = paymentGateway;this.emailNotifier = emailNotifier;this.auditLogger = auditLogger;}
}

5.2 避免部分初始化状态

// 构造函数注入确保完全初始化
@Service 
public class CompleteService {private final DependencyA depA;private final DependencyB depB;private final DependencyC depC;public CompleteService(DependencyA depA, DependencyB depB, DependencyC depC) {this.depA = depA;this.depB = depB;this.depC = depC;// 对象创建后立即处于可用状态}
}// Setter注入可能导致部分初始化
@Service
public class PartialService {private DependencyA depA;private DependencyB depB;@Autowiredpublic void setDepA(DependencyA depA) { this.depA = depA; }// 忘记添加setDepB方法,导致depB为nullpublic void someMethod() {depA.doSomething();  // OKdepB.doAnother();    // NPE!}
}

6. Spring官方推荐演进

历史背景:

  • Spring 4.3之前:需要@Autowired注解
  • Spring 4.3开始:单个构造函数的类可以省略@Autowired
  • Spring Boot 2.x:全面推荐构造函数注入
// Spring 4.3+ 的简化写法
@Service
public class UserService {private final UserRepository userRepository;// 单个构造函数时,@Autowired可省略public UserService(UserRepository userRepository) {this.userRepository = userRepository;}
}

7. 实际应用场景

7.1 必需依赖 vs 可选依赖

@Service
public class ComplexService {// 必需依赖:通过构造函数注入private final UserRepository userRepository;private final PaymentService paymentService;// 可选依赖:通过Setter注入(较少使用)private CacheManager cacheManager;// 必需依赖public ComplexService(UserRepository userRepository, PaymentService paymentService) {this.userRepository = userRepository;this.paymentService = paymentService;}// 可选依赖@Autowired(required = false)public void setCacheManager(CacheManager cacheManager) {this.cacheManager = cacheManager;}
}

7.2 Lombok简化代码

@Service
@RequiredArgsConstructor  // 为final字段生成构造函数
public class UserService {private final UserRepository userRepository;private final EmailService emailService;private final AuditService auditService;// Lombok自动生成:// public UserService(UserRepository userRepository, EmailService emailService, AuditService auditService) {//     this.userRepository = userRepository;//     this.emailService = emailService;//     this.auditService = auditService;// }
}

总结

Spring推荐构造函数注入的主要原因:

优势说明
不可变性final字段确保依赖不会被意外修改
完整性保证对象创建时所有依赖必须就绪
易于测试不需要Spring容器即可创建实例
循环依赖检测启动时就能发现设计问题
代码清晰明确表达对象的依赖关系
线程安全不可变对象天然线程安全

这种实践符合面向对象设计原则,特别是依赖倒置原则单一职责原则,能够显著提高代码的质量和可维护性。

http://www.dtcms.com/a/411414.html

相关文章:

  • 【读书笔记】架构整洁之道 P4 组件构建原则
  • (20)ASP.NET Core2.2 EF创建模型(必需属性和可选属性、最大长度、并发标记、阴影属性)
  • 优化软件哪个好优化技术
  • 【Python】微博超话一键签到工具
  • 关于网站推广wordpress啥时候出现的
  • 软件测试面试八股文:测试技术 10 大核心考点(二)
  • 雷达目标跟踪中扩展卡尔曼滤波(EKF)算法matlab实现
  • 初识网络:网络基础
  • 济南快速网站制作公司百度秒收录的网站
  • GitHub 热榜项目 - 日榜(2025-09-26)
  • 网站开发做什么简单制作表白网站
  • Java面试宝典:网络协议与Netty一
  • LinuxWindows环境下Nacos3.1.0详细安装配置指南:从零到生产就绪
  • 微信微网站 留言板网络营销的模式主要有
  • 实战训练1笔记
  • 网站制作程序下载ngo网页模板下载
  • C++学习记录(13)二叉排序树
  • TongWeb下如何获取数据源的物理连接?
  • 保险资料网站有哪些三网合一网站建设报价
  • 网站建设系统分析ai的优点和缺点
  • 三网合一网站百度一下免费下载
  • 坤驰科技携数据采集解决方案,亮相中国光纤传感大会
  • 可以做免费的网站吗广州平面设计工作室
  • 【文献阅读】基于机器学习的网络最差鲁棒性可扩展快速评估框架
  • 【复习】计网每日一题--PPP协议透明传输
  • 【训练技巧】torch.amp.GradScaler 里面当scale系数为0或者非常小的时候,详细分析与解决思路
  • 一站式服务logo设计深圳网站建设服务商哪些好?
  • 专业的网站建设公司电话做商城网站要什么手续
  • mdBook 开源笔记
  • 【1、Kotlin 基础语法】2、Kotlin 变量