第一部分:业务逻辑层概述

理解Service层在分层架构中的核心作用与职责

学习目标

掌握业务逻辑层的定位、核心职责及其在系统架构中的作用

1

什么是业务逻辑层?

业务逻辑层(Service层)是分层架构中的核心组件,负责:

  • 封装业务规则和流程
  • 处理复杂的业务逻辑
  • 协调多个数据访问对象(DAO/Repository)的操作
  • 提供事务管理支持
  • 处理业务异常
2

Service层的核心职责

  • 实现业务规则和验证
  • 协调多个Repository操作
  • 管理事务边界
  • 提供业务逻辑的抽象接口
  • 实现领域逻辑
  • 处理业务异常和错误

架构师提示

良好的Service层设计应该遵循"单一职责原则",每个Service类应该聚焦于一个特定的业务领域,避免创建"上帝对象"。同时,Service层应该保持对持久化技术的透明性,不直接依赖具体的数据库实现。

第二部分:分层架构设计

理解Service层在整体架构中的位置与协作关系

学习目标

掌握典型的分层架构设计,理解各层之间的依赖关系

Controller
Service
Repository
Database

分层架构中的依赖关系

  • Controller层:接收HTTP请求,调用Service方法,返回响应
  • Service层:实现业务逻辑,调用多个Repository,管理事务
  • Repository层:提供数据访问接口,执行CRUD操作
  • Model层:包含实体类、DTO、VO等数据对象

设计原则

Service层应遵循"依赖倒置原则":

  • 高层模块(Controller)不应依赖低层模块(Repository),两者都应依赖抽象
  • 抽象不应依赖细节,细节应依赖抽象
  • 使用接口定义服务契约,提供多种实现的可能性

第三部分:Service层实现

从接口定义到方法实现的完整开发流程

学习目标

掌握如何设计和实现一个完整的Service类

Service接口定义

public interface OrderService { /** * 创建新订单 * @param orderDto 订单DTO对象 * @return 创建成功的订单 * @throws BusinessException 业务异常 */ OrderVO createOrder(OrderDTO orderDto) throws BusinessException; /** * 取消订单 * @param orderId 订单ID * @throws OrderNotFoundException 订单不存在异常 */ void cancelOrder(Long orderId) throws OrderNotFoundException; // 其他业务方法... }

Service实现类

import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class OrderServiceImpl implements OrderService { private final OrderRepository orderRepository; private final InventoryService inventoryService; private final PaymentService paymentService; // 使用构造器注入依赖 public OrderServiceImpl(OrderRepository orderRepository, InventoryService inventoryService, PaymentService paymentService) { this.orderRepository = orderRepository; this.inventoryService = inventoryService; this.paymentService = paymentService; } @Override @Transactional(rollbackFor = BusinessException.class) public OrderVO createOrder(OrderDTO orderDto) throws BusinessException { // 1. 验证库存 if (!inventoryService.checkInventory(orderDto.getProductId(), orderDto.getQuantity())) { throw new BusinessException("库存不足"); } // 2. 创建订单实体 Order order = new Order(); // 设置订单属性... // 3. 扣减库存 inventoryService.deductInventory(orderDto.getProductId(), orderDto.getQuantity()); // 4. 处理支付 PaymentResult paymentResult = paymentService.processPayment(orderDto.getPaymentInfo()); if (!paymentResult.isSuccess()) { // 支付失败,回滚事务 throw new BusinessException("支付失败:" + paymentResult.getMessage()); } // 5. 保存订单 Order savedOrder = orderRepository.save(order); // 6. 返回订单VO return convertToVO(savedOrder); } // 其他方法实现... }

开发实践要点

  • 始终基于接口编程,提高代码可测试性和可扩展性
  • 使用构造器注入依赖,避免字段注入
  • 每个方法应专注于单一业务目标
  • 方法命名应清晰表达业务意图
  • 避免在Service层直接操作数据库
  • 保持Service方法无状态,避免存储业务状态

第四部分:事务管理

确保业务操作的原子性和数据一致性

学习目标

掌握Spring事务管理机制,实现可靠的事务控制

1. 业务方法开始
2. 开启事务
3. 执行业务操作
4. 成功完成?
5. 提交事务
6. 出现异常?
7. 回滚事务

声明式事务管理

@Service public class OrderServiceImpl implements OrderService { @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 30, rollbackFor = {BusinessException.class, SQLException.class}) public OrderVO createOrder(OrderDTO orderDto) { // 业务逻辑... } @Transactional(propagation = Propagation.REQUIRES_NEW) public void updateInventory(Long productId, int quantity) { // 更新库存... } }

传播行为

  • REQUIRED:默认值,支持当前事务,不存在则新建
  • SUPPORTS:支持当前事务,不存在则以非事务执行
  • REQUIRES_NEW:新建事务,挂起当前事务
  • NOT_SUPPORTED:非事务执行,挂起当前事务
  • NEVER:非事务执行,存在事务则抛异常
  • NESTED:嵌套事务执行

隔离级别

  • DEFAULT:使用数据库默认隔离级别
  • READ_UNCOMMITTED:读未提交(最低)
  • READ_COMMITTED:读已提交(推荐)
  • REPEATABLE_READ:可重复读
  • SERIALIZABLE:串行化(最高)

常见事务错误

  • 事务方法调用同一个类中的非事务方法
  • 未正确配置rollbackFor导致异常不回滚
  • 事务方法执行时间过长导致锁超时
  • 嵌套事务配置不当导致数据不一致
  • 在事务方法中处理不应该在事务中的操作(如发送邮件)

第五部分:异常处理

构建健壮的业务异常处理机制

学习目标

掌握业务异常的设计原则和统一处理方式

自定义业务异常

public class BusinessException extends RuntimeException { private final String errorCode; private final String errorMessage; public BusinessException(String errorCode, String errorMessage) { super(errorMessage); this.errorCode = errorCode; this.errorMessage = errorMessage; } // Getters... } public class OrderNotFoundException extends BusinessException { public OrderNotFoundException(Long orderId) { super("ORDER_NOT_FOUND", "订单不存在,ID: " + orderId); } }

全局异常处理

@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(BusinessException.class) public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) { ErrorResponse errorResponse = new ErrorResponse( ex.getErrorCode(), ex.getErrorMessage(), LocalDateTime.now() ); return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); } @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex) { ErrorResponse errorResponse = new ErrorResponse( "SYSTEM_ERROR", "系统内部错误,请联系管理员", LocalDateTime.now() ); return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); } }

异常处理最佳实践

  • 为不同的业务错误定义特定的异常类
  • 使用异常代码(errorCode)而非字符串匹配
  • 在Service层抛出业务异常,在Controller层处理
  • 避免在Service层捕获异常后直接记录日志
  • 使用全局异常处理器统一处理异常
  • 不要使用异常来控制业务逻辑流

第六部分:单元测试

确保业务逻辑的正确性与可靠性

学习目标

掌握使用JUnit和Mockito进行Service层单元测试

Service层单元测试示例

import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) class OrderServiceTest { @Mock private OrderRepository orderRepository; @Mock private InventoryService inventoryService; @Mock private PaymentService paymentService; @InjectMocks private OrderServiceImpl orderService; @Test void createOrder_Success() { // 1. 准备测试数据 OrderDTO orderDto = new OrderDTO(1L, 2, "CREDIT_CARD"); Order expectedOrder = new Order(1L, 2, "PENDING"); // 2. 模拟依赖行为 Mockito.when(inventoryService.checkInventory(1L, 2)).thenReturn(true); Mockito.when(paymentService.processPayment(any())).thenReturn(new PaymentResult(true, "Success")); Mockito.when(orderRepository.save(any())).thenReturn(expectedOrder); // 3. 执行测试方法 OrderVO result = orderService.createOrder(orderDto); // 4. 验证结果 Assertions.assertNotNull(result); Assertions.assertEquals(1L, result.getId()); Assertions.assertEquals("PENDING", result.getStatus()); // 5. 验证依赖调用 Mockito.verify(inventoryService).deductInventory(1L, 2); Mockito.verify(orderRepository).save(any()); } @Test void createOrder_InventoryCheckFailed() { // 准备测试数据 OrderDTO orderDto = new OrderDTO(1L, 10, "CREDIT_CARD"); // 模拟库存检查失败 Mockito.when(inventoryService.checkInventory(1L, 10)).thenReturn(false); // 验证抛出业务异常 BusinessException exception = Assertions.assertThrows(BusinessException.class, () -> orderService.createOrder(orderDto)); // 验证异常消息 Assertions.assertEquals("库存不足", exception.getErrorMessage()); } }

测试覆盖策略

  • 覆盖所有主要业务路径
  • 测试边界条件
  • 测试异常场景
  • 验证事务行为
  • 测试并发情况

测试数据准备

  • 使用Builder模式创建测试对象
  • 使用随机数据生成器
  • 准备边界值数据
  • 使用内存数据库
  • 避免依赖外部服务

测试执行策略

  • 单元测试应快速执行
  • 测试之间相互独立
  • 避免测试业务逻辑实现细节
  • 使用测试容器技术
  • 集成测试覆盖端到端流程

第七部分:常见错误

避免Service层开发的常见陷阱

学习目标

识别并避免业务逻辑层开发的常见错误模式

1. 过度复杂的Service

单个Service类包含过多方法,承担太多职责

解决方法:根据业务领域拆分Service,遵循单一职责原则

2. 事务范围不当

事务范围过大导致性能问题,或过小导致数据不一致

解决方法:合理设置事务边界,只对需要事务的方法添加@Transactional

3. 异常处理不当

在Service层捕获异常后仅记录日志未抛出,导致事务未回滚

解决方法:在Service层抛出业务异常,由全局异常处理器处理

4. 循环依赖

ServiceA依赖ServiceB,同时ServiceB又依赖ServiceA

解决方法:重构代码提取公共逻辑,使用接口隔离,引入第三方类

5. 业务逻辑泄漏

业务逻辑写在Controller或Repository层

解决方法:严格分层,确保业务逻辑仅存在于Service层

6. 忽略并发问题

未考虑高并发场景下的数据一致性问题

解决方法:使用乐观锁、分布式锁、队列等机制处理并发

第八部分:最佳实践

构建高质量业务逻辑层的实用指南

学习目标

掌握业务逻辑层开发的最佳实践和设计模式

分层设计

  • 严格遵循分层架构
  • 使用接口定义服务契约
  • 领域模型与数据模型分离
  • 使用DTO在不同层间传输数据

事务管理

  • 在Service层定义事务边界
  • 设置合理的事务超时时间
  • 避免在事务中执行远程调用
  • 使用@Transactional(readOnly=true)优化查询

异常处理

  • 使用特定业务异常
  • 全局统一异常处理
  • 提供有意义的错误信息
  • 区分业务异常和系统异常

设计模式

  • 策略模式:封装可替换的算法
  • 模板方法:定义算法骨架
  • 工厂模式:创建复杂对象
  • 门面模式:简化复杂子系统调用

性能优化

  • 避免N+1查询问题
  • 批量处理数据库操作
  • 使用缓存减少数据库访问
  • 异步处理耗时操作

可测试性

  • 依赖接口而非具体实现
  • 使用依赖注入
  • 避免静态方法和单例
  • 分离业务逻辑和基础设施

开发检查清单

  • ✅ 业务逻辑仅存在于Service层
  • ✅ 每个Service类职责单一
  • ✅ 使用接口定义服务契约
  • ✅ 事务边界设置合理
  • ✅ 异常处理机制完善
  • ✅ 单元测试覆盖主要业务路径
  • ✅ 性能关键操作经过优化
  • ✅ 代码符合编码规范