news 2026/4/12 10:51:36

Spring+DDD实战:从贫血模型到领域驱动的架构演进

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring+DDD实战:从贫血模型到领域驱动的架构演进

Spring+DDD实战:从贫血模型到领域驱动的架构演进

【免费下载链接】spring-reading涵盖了 Spring 框架的核心概念和关键功能,包括控制反转(IOC)容器的使用,面向切面编程(AOP)的原理与实践,事务管理的方式与实现,Spring MVC 的流程与控制器工作机制,以及 Spring 中数据访问、安全、Boot 自动配置等方面的深入研究。此外,它还包含了 Spring 事件机制的应用、高级主题如缓存抽象和响应式编程,以及对 Spring 源码的编程风格与设计模式的深入探讨。项目地址: https://gitcode.com/GitHub_Trending/sp/spring-reading

引言:一个典型的架构困境

"我们的代码越来越难改了!"——这是很多开发团队在业务系统演进到一定阶段后的共同感慨。随着功能不断叠加,原本清晰的MVC架构逐渐演变成"大泥球"(Big Ball of Mud),业务逻辑分散在Controller、Service和DAO中,修改一个简单的业务规则需要改动多个文件。

让我们从一个真实案例开始:用户积分系统。在传统架构下,代码可能是这样的:

// 贫血模型示例 - 业务逻辑分散在各处 @Service public class PointService { public void transferPoints(Long fromUserId, Long toUserId, int amount) { // 在Service中验证业务规则 if (amount <= 0) { throw new IllegalArgumentException("积分数量必须大于0"); } Point fromPoints = pointDao.findByUserId(fromUserId); Point toPoints = pointDao.findByUserId(toUserId); // 在Service中执行核心业务逻辑 if (fromPoints.getBalance() < amount) { throw new InsufficientPointsException("积分不足"); } fromPoints.setBalance(fromPoints.getBalance() - amount); toPoints.setBalance(toPoints.getBalance() + amount); pointDao.update(fromPoints); pointDao.update(toPoints); } }

这种贫血模型的问题在于:业务逻辑分散在Service层,领域对象只是数据的载体,缺乏真正的行为封装。

架构演进:从分层到领域驱动

第一步:识别核心领域概念

在积分系统中,我们需要识别出真正的领域对象

  • User(用户):系统的主体
  • Point(积分):用户的积分资产
  • PointTransaction(积分交易):积分转移的记录

第二步:重构为富领域模型

// 富领域模型 - 积分实体 public class Point { private Long userId; private int balance; // 构造函数 public Point(Long userId, int balance) { this.userId = userId; this.balance = balance; } // 领域行为:增加积分 public void add(int amount) { if (amount <= 0) { throw new IllegalArgumentException("增加积分必须大于0"); } this.balance += amount; } // 领域行为:减少积分 public void subtract(int amount) { if (amount <= 0) { throw new IllegalArgumentException("减少积分必须大于0"); } if (this.balance < amount) { throw new InsufficientPointsException("积分不足"); } this.balance -= amount; } // 查询方法 public boolean canSubtract(int amount) { return this.balance >= amount; } }

第三步:设计领域服务

当业务逻辑涉及多个实体时,使用领域服务来封装:

// 积分领域服务 @Service public class PointDomainService { private final PointRepository pointRepository; public PointDomainService(PointRepository pointRepository) { this.pointRepository = pointRepository; } @Transactional public PointTransaction transfer(TransferCommand command) { Point fromPoint = pointRepository.findByUserId(command.getFromUserId()); Point toPoint = pointRepository.findByUserId(command.getToUserId()); // 执行领域逻辑 fromPoint.subtract(command.getAmount()); toPoint.add(command.getAmount()); // 保存变更 pointRepository.save(fromPoint); pointRepository.save(toPoint); // 记录交易 return PointTransaction.recordTransfer(command); } }

Spring框架的DDD实现技巧

依赖注入:解耦领域与基础设施

Spring的构造函数注入是实现DDD分层的关键:

// 应用服务 - 协调领域服务和外部交互 @Service public class PointApplicationService { private final PointDomainService pointDomainService; private final EventPublisher eventPublisher; // 构造函数注入,依赖关系明确 public PointApplicationService(PointDomainService pointDomainService, EventPublisher eventPublisher) { this.pointDomainService = pointDomainService; this.eventPublisher = eventPublisher; } public void handleTransfer(TransferRequest request) { // 1. 参数验证 validateRequest(request); // 2. 执行核心领域逻辑 PointTransaction transaction = pointDomainService.transfer(request.toCommand()); // 3. 发布领域事件 eventPublisher.publish(new PointsTransferredEvent(transaction)); } }

事务管理:保证领域操作的原子性

使用Spring的声明式事务确保领域操作的完整性:

// 在配置类中启用事务管理 @Configuration @EnableTransactionManagement public class TransactionConfig { @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }

仓储模式:隔离数据访问细节

仓储接口定义在领域层,实现放在基础设施层:

// 领域层 - 仓储接口 public interface PointRepository { Point findByUserId(Long userId); void save(Point point); // 其他查询方法... } // 基础设施层 - 仓储实现 @Repository public class JdbcPointRepository implements PointRepository { private final JdbcTemplate jdbcTemplate; public JdbcPointRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override public Point findByUserId(Long userId) { // 数据访问实现 String sql = "SELECT * FROM points WHERE user_id = ?"; return jdbcTemplate.queryForObject(sql, new PointRowMapper(), userId); } }

实战演练:构建完整的DDD应用

项目结构设计

src/main/java/com/example/pointsystem/ ├── application/ # 应用层 │ ├── command/ # 命令对象 │ ├── service/ # 应用服务 │ └── event/ # 应用事件 ├── domain/ # 领域层 │ ├── model/ # 领域模型 │ ├── service/ # 领域服务 │ ├── repository/ # 仓储接口 │ └── event/ # 领域事件 ├── infrastructure/ # 基础设施层 │ ├── persistence/ # 持久化实现 │ ├── external/ # 外部服务调用 │ └── config/ # 配置类 └── interfaces/ # 接口层 ├── rest/ # REST API └── dto/ # 数据传输对象

核心领域模型实现

// 聚合根 - 用户 public class User { private Long id; private String username; private UserStatus status; private Point point; // 聚合内的实体引用 // 工厂方法 public static User create(String username) { User user = new User(); user.id = IdGenerator.nextId(); user.username = username; user.status = UserStatus.ACTIVE; user.point = new Point(user.id, 0); return user; } // 领域行为 public void activate() { if (this.status == UserStatus.DISABLED) { this.status = UserStatus.ACTIVE; } } // 业务方法 public void transferPointsTo(User targetUser, int amount) { // 验证业务规则 if (!this.isActive() || !targetUser.isActive()) { throw new BusinessException("用户状态异常"); } // 执行积分转移 this.point.subtract(amount); targetUser.point.add(amount); // 记录领域事件 DomainEventPublisher.publish(new PointsTransferredEvent(this.id, targetUser.id, amount)); } }

避坑指南:DDD实践中的常见问题

问题1:过度设计

症状:为每个简单的业务概念都创建聚合、实体、值对象。

解决方案:从简单开始,只有当业务复杂性确实需要时才引入DDD概念。

问题2:技术实现污染领域模型

症状:在领域对象中引入JPA注解、JSON序列化等基础设施关注点。

解决方案:使用防腐层隔离技术细节:

// 领域模型 - 纯粹的POJO public class Point { private Long userId; private int balance; // 纯粹的领域行为,无技术依赖 public void add(int amount) { this.balance += amount; } } // 基础设施层 - 映射配置 @Entity @Table(name = "points") public class PointJpaEntity { @Id private Long userId; private int balance; // 转换为领域模型 public Point toDomainModel() { return new Point(this.userId, this.balance); } }

问题3:事务边界设计不当

症状:一个事务中包含过多的业务操作,导致锁竞争和性能问题。

解决方案每个事务对应一个用例,避免跨聚合的长事务。

架构收益:从混乱到有序

采用DDD架构后,我们的系统获得了显著的改进:

  1. 业务逻辑集中:积分相关的所有规则都在Point实体中
  2. 代码可读性提升:通过领域对象的方法名就能理解业务意图
  3. 测试更容易:可以独立测试领域对象的行为
  4. 演进更安全:修改业务规则时影响范围明确

总结:DDD不是银弹,而是工具箱

Spring框架为DDD实践提供了强大的基础设施支持,但成功的关键在于:

  • 渐进式重构:不要试图一次性重构整个系统
  • 团队共识:确保团队成员理解并认同DDD的价值
  • 持续改进:在实践中不断调整和优化架构设计

记住:好的架构是演进而来的,不是设计出来的。从识别当前架构的问题开始,逐步引入DDD概念,让架构服务于业务,而不是业务服务于架构。

【免费下载链接】spring-reading涵盖了 Spring 框架的核心概念和关键功能,包括控制反转(IOC)容器的使用,面向切面编程(AOP)的原理与实践,事务管理的方式与实现,Spring MVC 的流程与控制器工作机制,以及 Spring 中数据访问、安全、Boot 自动配置等方面的深入研究。此外,它还包含了 Spring 事件机制的应用、高级主题如缓存抽象和响应式编程,以及对 Spring 源码的编程风格与设计模式的深入探讨。项目地址: https://gitcode.com/GitHub_Trending/sp/spring-reading

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/8 23:53:43

风格迁移拓展:除了还原色彩,还能模拟油画、水墨等效果?

风格迁移拓展&#xff1a;除了还原色彩&#xff0c;还能模拟油画、水墨等效果&#xff1f; 在数字影像日益普及的今天&#xff0c;那些泛黄的老照片却承载着无法替代的情感价值。然而&#xff0c;黑白图像的单调性、褪色与破损问题长期困扰着家庭用户与专业机构——如何让一张百…

作者头像 李华
网站建设 2026/4/9 9:59:23

告别手忙脚乱!FF14钓鱼神器渔人的直感5大核心优势详解

告别手忙脚乱&#xff01;FF14钓鱼神器渔人的直感5大核心优势详解 【免费下载链接】Fishers-Intuition 渔人的直感&#xff0c;最终幻想14钓鱼计时器 项目地址: https://gitcode.com/gh_mirrors/fi/Fishers-Intuition 还在为错过幻海流而懊悔不已&#xff1f;被稀有鱼种…

作者头像 李华
网站建设 2026/4/3 11:34:55

B站视频下载神器:如何一键保存高清视频到本地永久收藏

B站视频下载神器&#xff1a;如何一键保存高清视频到本地永久收藏 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader &#x1f633; 项目地址: https://gitcode.com/gh_mirrors/b…

作者头像 李华
网站建设 2026/4/5 23:31:21

如何高效使用IDR:交互式Delphi反编译器的完整指南

如何高效使用IDR&#xff1a;交互式Delphi反编译器的完整指南 【免费下载链接】IDR Interactive Delphi Reconstructor 项目地址: https://gitcode.com/gh_mirrors/id/IDR IDR&#xff08;Interactive Delphi Reconstructor&#xff09;是一款专为Windows32环境设计的强…

作者头像 李华
网站建设 2026/4/8 14:28:02

如何高效实现跨平台音乐地址解析:music-api完整技术方案解析

在音乐应用开发中&#xff0c;开发者常常面临多平台音乐资源整合的技术挑战。各大音乐平台接口差异大、协议复杂、更新频繁&#xff0c;导致音乐地址解析成为开发过程中的技术瓶颈。music-api项目通过创新的跨平台音乐解析技术&#xff0c;为开发者提供了一套完整的多源音乐地址…

作者头像 李华
网站建设 2026/4/11 1:24:20

HomeAssistant格力空调组件:智能家居温控终极解决方案

让您的格力空调秒变智能设备&#xff01;这款专为Home Assistant平台设计的自定义组件&#xff0c;采用先进的Python3技术栈&#xff0c;完美支持Gree通信协议&#xff0c;为您打造真正意义上的本地化智能温控体验。 【免费下载链接】HomeAssistant-GreeClimateComponent Custo…

作者头像 李华