在Spring Boot 开发中 Bean 的声明和依赖注入最佳的组合方式是什么?

在Spring Boot 开发中,社区和 Spring 官方已经形成了一套非常明确的最佳实践。这个黄金组合就是:

  • Bean 声明:使用构造型注解(Stereotype Annotations),如 @Service, @Repository, @Component 等。
  • 依赖注入:使用构造函数注入(Constructor Injection)

下面我们来详细拆解为什么这个组合是最佳选择,并给出最终的“代码范本”。


1. Bean 声明:使用构造型注解

构造型注解是 Spring 提供的、用于标记一个类为 Bean 的特殊注解。它们不仅告诉 IoC 容器“请管理我”,还赋予了这个 Bean 语义上的角色

  • @Service: 用于标记业务逻辑层(Service Layer)的组件。
  • @Repository: 用于标记数据访问层(Data Access Layer)的组件,它还能帮助转换特定于数据源的异常。
  • @Controller / @RestController: 用于标记表现层(Presentation Layer),处理 HTTP 请求。
  • @Component: 一个通用的构造型,当一个 Bean 不适合归入以上任何一类时使用。
  • @Configuration: 用于声明一个类为配置类,通常与 @Bean 方法一起使用。

为什么推荐这样做?

  • 代码清晰,见名知意:当你看到一个类被 @Service 标记,你立刻就知道它的职责是处理业务逻辑,这大大提高了代码的可读性。
  • 符合分层架构思想:这种方式天然地鼓励开发者遵循经典的三层(或多层)架构模式。
  • 便于 AOP 切入:一些 Spring AOP 功能(如事务管理)可以更容易地针对特定角色的 Bean(如所有 @Repository)设置切面。

2. 依赖注入:强烈推荐构造函数注入

这是整个最佳实践的核心。Spring 支持三种主要的注入方式:字段注入、Setter 注入和构造函数注入。构造函数注入是官方和社区一致推荐的方式。

为什么构造函数注入是最好的?

1. 保证依赖的不可变性(Immutability)
你可以将依赖字段声明为 final,这意味着一旦对象被创建,它的依赖就不能再被改变。这使得你的组件更加健壮和线程安全。

@Service
public class MyService {private final MyRepository repository; // final!public MyService(MyRepository repository) {this.repository = repository;}
}

2. 保证依赖的可用性(Non-Nullability)
使用构造函数注入,可以确保在对象被创建的那一刻,它所必需的依赖就已经被注入了。你永远不会在后续的方法调用中遇到一个因忘记注入而导致的 NullPointerException。对象要么被成功创建(带着所有依赖),要么在创建时就失败。

3. 清晰地暴露组件的依赖关系
一个类的所有必需依赖都清晰地列在构造函数的参数列表中。这就像一个“组件合同”,任何人一看就知道要创建这个类的实例需要提供哪些东西。这有助于防止一个类拥有过多的依赖(构造函数会变得非常长),促使你进行重构。

4. 极大地提升了可测试性(Crucial for Unit Testing)
这是最重要的一点。使用构造函数注入,你的类不再强依赖于 Spring 容器。在进行单元测试时,你可以非常轻松地手动创建类的实例,并传入一个模拟(Mock)的依赖对象。

对比一下字段注入的窘境:

// 反模式:字段注入
@Service
public class BadService {@Autowiredprivate MyRepository repository; // 无法声明为 finalpublic String getUserName() {return repository.findUser();}
}// 如何测试 BadService?
// 你不能直接 new BadService(),因为 repository 会是 null!
// 你必须借助 Spring Test 或 Mockito 的 @InjectMocks 等工具,增加了测试的复杂性。

再看构造函数注入的优雅测试:

// 推荐模式:构造函数注入
@Service
public class GoodService {private final MyRepository repository;public GoodService(MyRepository repository) {this.repository = repository;}public String getUserName() {return repository.findUser();}
}// 测试 GoodService 非常简单
@Test
void testGetUserName() {// 1. 创建一个 Mock 依赖MyRepository mockRepo = Mockito.mock(MyRepository.class);Mockito.when(mockRepo.findUser()).thenReturn("Mocked User");// 2. 手动创建被测试对象,注入 Mock 依赖GoodService service = new GoodService(mockRepo);// 3. 执行测试assertEquals("Mocked User", service.getUserName());
}

黄金组合:最终的代码范本 (结合 Lombok)

在现代开发中,为了减少编写构造函数的样板代码,我们通常会使用 Lombok 库。@RequiredArgsConstructor 注解可以自动为所有 final 字段生成一个构造函数。

这就是目前最流行、最高效的实践方式:

1. 数据访问层 (Repository)

import org.springframework.stereotype.Repository;@Repository
public class UserRepository {public String findUserById(Long id) {// ... 数据库查询逻辑 ...return "User " + id;}
}

2. 业务逻辑层 (Service)

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;@Service
@RequiredArgsConstructor // Lombok: 自动为 final 字段生成构造函数
public class UserService {// 依赖被声明为 final,通过构造函数注入private final UserRepository userRepository;private final EmailService emailService; // 可以有多个依赖public void registerUser(Long userId) {String userName = userRepository.findUserById(userId);emailService.sendWelcomeEmail(userName);System.out.println(userName + " has been registered.");}
}

3. 表现层 (Controller)

import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequiredArgsConstructor // 同样使用 Lombok
public class UserController {// 依赖 Service,同样声明为 finalprivate final UserService userService;@GetMapping("/users/{id}/register")public String registerUser(@PathVariable Long id) {userService.registerUser(id);return "User " + id + " registration process started.";}
}

总结

方面推荐方式理由
Bean 声明@Service, @Repository, @Controller 等构造型注解语义清晰、代码可读性高、符合分层架构
依赖注入构造函数注入 (通常配合 Lombok 的 @RequiredArgsConstructor)保证依赖不可变 (final)、保证依赖非空、依赖关系清晰、极易进行单元测试

遵循这套“黄金组合”,我们的 Spring Boot 应用将会拥有一个清晰、健壮、高内聚、低耦合且易于测试的架构基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88888.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88888.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oxygen XML Editor 26.0编辑器

Oxygen XML Editor 26.0编辑器 欢迎使用Oxygen XML Editor 26.0编辑器准备工作安装javajdk安装jdk验证Oxygen XML Editor 26.0安装欢迎使用Oxygen XML Editor 26.0编辑器 准备工作安装java Java官网下载地址:https://www.oracle.com/java/technologies/ Oxygen XML Editor 2…

AWS Lambda Container 方式部署 Flask 应用并通过 API Gateway 提供访问

前言 一年前写过一篇 Lambda 运行 Flask 应用的博文: https://lpwmm.blog.csdn.net/article/details/139756140 当时使用的是 ZIP 包方式部署应用代码, 对于简单的 API 开发用起来还是可以的, 但是如果需要集成到 CI/CD pipeline 里面就有点不太优雅. 本文将介绍使用容器方式…

React虚拟DOM的进化之路

引言 在Web前端开发中,用户交互的流畅性和页面性能一直是核心挑战。早期,开发者直接操作真实DOM(Document Object Model)时,频繁的重排(reflow)和重绘(repaint)导致性能…

(7)机器学习小白入门 YOLOv:机器学习模型训练详解

— (1)机器学习小白入门YOLOv :从概念到实践 (2)机器学习小白入门 YOLOv:从模块优化到工程部署 (3)机器学习小白入门 YOLOv: 解锁图片分类新技能 (4)机器学习小白入门YOLOv :图片标注实操手册 (5)机器学习小白入门 YOLOv&#xff…

初识MySQL(三)之主从配置与读写分离实战

主重复制 主重复制原理master开启二进制日志记录slave开启IO进程,从master中读取二进制日志并写入slave的中继日志slave开启SQL进程,从中继日志中读取二进制日志并进行重放最终,达到slave与master中数据一致的状态,我们称作为主从…

RabbitMQ面试精讲 Day 2:RabbitMQ工作模型与消息流转

【RabbitMQ面试精讲 Day 2】RabbitMQ工作模型与消息流转 开篇 欢迎来到"RabbitMQ面试精讲"系列的第2天,今天我们将深入探讨RabbitMQ的工作模型与消息流转机制。这是面试中最常被问到的核心知识点之一,90%的RabbitMQ面试都会涉及消息流转流程…

基于SpringBoot3集成Kafka集群

1. build.gradle依赖引入 implementation org.springframework.kafka:spring-kafka:3.2.02. 新增kafka-log.yml文件 在resource/config下面新增kafka-log.yml,配置主题与消费者组 # Kafka消费者群组 kafka:consumer:group:log-data: log-data-grouptopic:log-data: …

wpf Canvas 导出图片

在WPF中将Canvas导出为图片主要涉及以下关键步骤和注意事项: ‌核心实现方法‌使用RenderTargetBitmap将Canvas渲染为位图,再通过PngBitmapEncoder保存为PNG文件。需注意临时移除Canvas的布局变换(LayoutTransform)以避免渲染异常‌1。示例代码片段:CanvasExporter.cs pu…

lvs负载均衡实操模拟

目录 一、配置准备 二、NET模式 修改LVS端 开启路由 修改对内网卡 ens160 修改对外网卡 ens224 加载网卡配置文件 修改web1端 修改网卡信息 重启网络 检测 配置web2 检测 验证配置是否正常 启动nginx服务 验证以上配置 添加lvs规则 验证 三、DR模式 修改…

Spring Boot 是如何简化 IoC 的配置的?

首先Spring Boot 并没有发明新的 IoC 理论,它做的也不是替换掉 Spring IoC 容器。相反,Spring Boot 是 Spring IoC 思想的实践者和简化者。它通过**“约定优于配置”(Convention over Configuration)**的理念,将原本繁…

Go语言中的组合式接口设计模式

文章目录Go语言中的组合式接口设计模式背景和需求组合式接口设计Go语言中的组合式接口设计模式 背景和需求 在微服务架构和复杂业务系统中,我们经常需要调用多个外部服务或内部模块。传统的做法是将所有方法都放在一个大接口中,但这种设计会导致接口臃…

React - createPortal

什么是createPortal&#xff1f;注意这是一个API&#xff0c;不是组件&#xff0c;他的作用是&#xff1a;将一个组件渲染到DOM的任意位置&#xff0c;跟Vue的Teleport组件类似。用法 import { createPortal } from react-dom;const App () > {return createPortal(<div…

Cursor的使用

Cursor的使用 Ctrl L 打开历史对话记录 Tab智能助手 1.单行/多行补全 已有代码片段&#xff1a; //需求&#xff1a;写一个工具类计算数组平均值 public class ArrayUtils {//按tab会完成补全 }按tab键- Cursor 自动生成代码: //需求&#xff1a;写一个工具类计算数组平均值 p…

17.使用DenseNet网络进行Fashion-Mnist分类

17.1 DenseNet网络结构设计import torch from torch import nn from torchsummary import summary #卷积层 def conv_block(input_channels,num_channels):netnn.Sequential(nn.BatchNorm2d(input_channels),nn.ReLU(),nn.Conv2d(input_channels,num_channels,kernel_size3,pad…

网安系列【16】之Weblogic和jboss漏洞

文章目录一 Weblogic1.1 Weblogic相关漏洞1.2 Weblogic漏洞发现1.3 Weblogic漏洞利用二 Jboss2.1 Jboss漏洞2.2 Jboss识别与漏洞利用一 Weblogic WebLogic 是由 Oracle公司 开发的一款基于Java EE&#xff08;现称Jakarta EE&#xff09;的企业级应用服务器&#xff0c;主要用…

Unity URP + XR 自定义 Skybox 在真机变黑问题全解析与解决方案(支持 Pico、Quest 等一体机)

在使用 Unity 的 URP 渲染管线开发 XR 应用&#xff08;如 Pico Neo、Pico 4、Quest 2/3 等一体机&#xff09;时&#xff0c;很多开发者遇到一个奇怪的问题&#xff1a;打包后&#xff0c;Skybox&#xff08;天空盒&#xff09;在某些角度下突然变黑&#xff0c;只在转动头部后…

Cursor、飞算JavaAI、GitHub Copilot、Gemini CLI 等热门 AI 开发工具合集

Cursor&#xff1a;代码编写的智能伙伴​Cursor 是 Anysphere 公司推出的一款 AI 编程工具&#xff0c;它基于微软开源代码编辑器 VS Code 开发&#xff0c;将 AI 技术深度整合到开发人员的工作流程中。Cursor 的功能十分强大&#xff0c;不仅能够自动用纯英文编写代码&#xf…

如何安装历史版本或指定版本的 git

背景 有的时候&#xff0c;我们需要安装指定版本的git&#xff0c;或者希望旧一点的&#xff0c;毕竟我就遇到最新的2.50.1在win10安装后打开就一闪而过&#xff0c;而安装2.49.1就不会 下载 官网可能比较难找&#xff0c;但是这个github仓库&#xff1a;https://github.com/gi…

LaCo: Large Language Model Pruning via Layer Collapse

发表&#xff1a;EMNLP_FINDING_2024 机构&#xff1a;Shanghai Jiao Tong University 连接&#xff1a;LaCo: Large Language Model Pruning via Layer Collapse - ACL Anthology 代码&#xff1a;https://github.com/yangyifei729/LaCo Abstract 基于 Transformer 的大语…

服务器内核级故障排查

目录 **检查内核级故障(Oops/Panic)的具体操作步骤****1. 查看完整 `dmesg` 日志(含时间戳)****2. 过滤关键错误信息****3. 检查系统日志中的内核消息****4. 分析最近一次启动的日志****5. 检查是否有 `vmcore` 转储文件****常见内核错误示例及含义**补充说明:检查内核级故…