news 2026/5/14 2:51:22

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/5/8 22:34:58

flatpickr深度解析:如何用20KB代码重构现代Web日期交互体验

flatpickr深度解析&#xff1a;如何用20KB代码重构现代Web日期交互体验 【免费下载链接】flatpickr 项目地址: https://gitcode.com/gh_mirrors/fla/flatpickr 当金融科技公司的产品经理面对复杂的报表系统&#xff0c;当电商平台的开发者处理促销活动的时间配置&#…

作者头像 李华
网站建设 2026/5/10 3:32:41

格力空调智能控制终极指南:HomeAssistant本地化集成方案

想要让您的格力空调变得更智能吗&#xff1f;HomeAssistant格力空调组件为您提供完整的本地化控制解决方案&#xff0c;无需依赖云端服务即可实现远程操控和自动化管理。这个基于Python3开发的自定义气候组件&#xff0c;专为支持Gree协议的空调设备设计&#xff0c;让您的智能…

作者头像 李华
网站建设 2026/5/9 10:13:10

OpenMTP:macOS与Android跨平台文件管理的专业解决方案

OpenMTP&#xff1a;macOS与Android跨平台文件管理的专业解决方案 【免费下载链接】openmtp OpenMTP - Advanced Android File Transfer Application for macOS 项目地址: https://gitcode.com/gh_mirrors/op/openmtp 在数字时代&#xff0c;macOS用户与Android设备间的…

作者头像 李华
网站建设 2026/5/12 3:35:03

星露谷农场规划器完全指南:5分钟打造完美农场布局

星露谷农场规划器完全指南&#xff1a;5分钟打造完美农场布局 【免费下载链接】stardewplanner Stardew Valley farm planner 项目地址: https://gitcode.com/gh_mirrors/st/stardewplanner 想在《星露谷物语》中设计出既实用又美观的农场布局吗&#xff1f;&#x1f31…

作者头像 李华
网站建设 2026/5/10 9:25:54

Spring DDD架构实战:从传统分层到领域驱动设计的演进之路

Spring DDD架构实战&#xff1a;从传统分层到领域驱动设计的演进之路 【免费下载链接】spring-reading 涵盖了 Spring 框架的核心概念和关键功能&#xff0c;包括控制反转&#xff08;IOC&#xff09;容器的使用&#xff0c;面向切面编程&#xff08;AOP&#xff09;的原理与实…

作者头像 李华
网站建设 2026/5/9 5:54:50

《流放之路》交易助手:从入门到精通的完整使用指南

在《流放之路》的复杂经济体系中&#xff0c;准确评估装备价值并高效完成交易是每个玩家必须掌握的技能。本文将为玩家详细介绍一款功能强大的交易辅助工具&#xff0c;帮助您从交易新手成长为市场专家。 【免费下载链接】awakened-poe-trade :heavy_dollar_sign: :hammer: Pat…

作者头像 李华