基于DDD的Java分层架构设计与框架实践
liuian 2025-07-27 21:59 11 浏览
一、分层架构的必要性
领域驱动设计(DDD)强调以业务领域为核心构建软件系统,分层架构通过明确的职责划分实现:
- 关注点分离:隔离业务复杂度与技术实现
- 可测试性:各层可独立测试验证
- 可维护性:领域模型演进不影响技术实现
- 技术无关性:领域层不依赖具体技术栈
二、DDD经典分层架构
1. 用户接口层(Interface Layer)
- 职责:处理用户请求,数据转换与校验
- 组件:
- java
@RestController
@RequiredArgsConstructor
public class OrderController {
private final OrderAppService orderAppService;
@PostMapping("/orders")
public ResponseEntity<OrderDTO> createOrder(@Valid @RequestBody CreateOrderRequest request) {
OrderDTO order = orderAppService.createOrder(request);
return ResponseEntity.created(URI.create("/orders/"+order.id())).body(order);
}
}
2. 应用层(Application Layer)
- 职责:协调领域对象完成业务用例
- 特点:
- 事务边界控制
- 无业务逻辑,仅流程编排
- java
@Service
@RequiredArgsConstructor
public class OrderAppService {
private final OrderRepository orderRepository;
private final DomainEventPublisher eventPublisher;
@Transactional
public OrderDTO createOrder(CreateOrderRequest request) {
Order order = OrderFactory.create(request);
orderRepository.save(order);
eventPublisher.publish(new OrderCreatedEvent(order));
return OrderAssembler.toDTO(order);
}
}
3. 领域层(Domain Layer)
- 核心:包含业务实体、值对象、领域服务
- 设计要点:
- 充血模型:行为与数据共存
- 保持技术无关性
- java
public class Order {
private OrderId id;
private List<OrderItem> items;
private OrderStatus status;
public void addItem(Product product, int quantity) {
items.add(new OrderItem(product, quantity));
recalculateTotal();
}
private void recalculateTotal() {
// 业务计算逻辑
}
}
@DomainService
public class PricingService {
public Money calculateDiscount(Order order) {
// 复杂的定价规则
}
}
4. 基础设施层(Infrastructure Layer)
- 职责:实现技术细节
- 典型组件:
- java
public class Order {
private OrderId id;
private List<OrderItem> items;
private OrderStatus status;
public void addItem(Product product, int quantity) {
items.add(new OrderItem(product, quantity));
recalculateTotal();
}
private void recalculateTotal() {
// 业务计算逻辑
}
}
@DomainService
public class PricingService {
public Money calculateDiscount(Order order) {
// 复杂的定价规则
}
}
三、框架选型建议
层级 | 推荐框架 | 作用说明 |
用户接口层 | Spring MVC/WebFlux | 请求处理与响应格式化 |
应用层 | Spring Core | 事务管理与依赖注入 |
领域层 | 无框架依赖 | 保持领域纯净性 |
基础设施层 | JPA/MyBatis, Spring Data | 持久化实现 |
MapStruct | DTO转换 | |
Axon Framework | 事件溯源支持 |
四、分层交互规范
- 严格单向依赖:
用户接口层 → 应用层 → 领域层
↖ ↖
基础设施层 ←─────┘
- 跨层调用规则:
- 禁止基础设施层直接调用领域层
- 领域对象不直接访问仓储接口
- DTO转换应在应用层完成
五、关键实践指南
1. 聚合根设计
java
public class Order {
// 对外暴露行为方法而非setter
public void cancel() {
verifyCancellable();
this.status = OrderStatus.CANCELLED;
registerDomainEvent(new OrderCancelledEvent(this));
}
private void verifyCancellable() {
if (status != OrderStatus.CREATED) {
throw new IllegalOrderStateException();
}
}
}
2. CQRS实现
java
// 命令端
public interface OrderCommandRepository {
void save(Order order);
}
// 查询端
public interface OrderQueryRepository {
List<OrderSummary> findOrdersByUser(String userId);
}
// 使用JPA Specification实现复杂查询
public class OrderSpecifications {
public static Specification<OrderEntity> statusIs(OrderStatus status) {
return (root, query, cb) -> cb.equal(root.get("status"), status);
}
}
3. 领域事件处理
java
复制
// 事件定义
public class OrderPaidEvent extends DomainEvent {
private String orderId;
private LocalDateTime paidTime;
}
// 事件处理器
@Component
public class OrderPaidEventHandler {
@EventListener
public void handle(OrderPaidEvent event) {
// 更新物流状态等后续处理
}
}
六、项目结构示例
复制
src/main/java
├── application
│ ├── dto
│ ├── service
│ └── assembler
├── domain
│ ├── model
│ ├── service
│ ├── event
│ └── repository
├── interfaces
│ ├── rest
│ ├── rpc
│ └── web
└── infrastructure
├── dao
├── config
└── external
七、常见问题规避
- 贫血模型反模式:避免仅有getter/setter的领域对象
- 层渗透问题:禁止基础设施层类型出现在领域层
- 事务管理:应用层控制事务边界,领域层保持无状态
- 性能优化:在基础设施层实现查询优化,不影响领域模型
八、演进建议
- 初期采用标准四层架构
- 业务复杂后引入六边形架构
- 高并发场景采用CQRS+Event Sourcing
- 微服务架构下配合领域事件实现最终一致性
通过遵循DDD分层原则,开发者可以构建出响应业务变化、核心逻辑清晰的高质量系统架构。关键在于保持领域层的纯粹性,通过分层隔离将技术复杂性下沉到基础设施实现中。
相关推荐
- 10种常见的MySQL错误,你可中招?
-
【51CTO.com快译】如果未能对MySQL8进行恰当的配置,您非但可能遇到无法顺利访问、或调用MySQL的窘境,而且还可能给真实的应用生产环境带来巨大的影响。本文列举了十种MySQL...
- MySQL主从如何保证数据一致性
-
MySQL主从(主备)搭建请点击基于Spring的数据库读写分离。MySQL主备基本原理假设主备切换前,我们的主库是节点A,节点B是节点A的备库,客户端的读写都是直接访问节点A,节点B只是将A的更新同...
- MySQL低版本升级操作流程
-
(关注“数据库架构师”公众号,提升数据库技能,助力职业发展)0-升级背景MySQL5.5发布于2010年,至今已有十年历史,官方已经停止更新。2008年发布的MySQL5.1版本,在2018年...
- MySQL数据库知识
-
MySQL是一种关系型数据库管理系统;那废话不多说,直接上自己以前学习整理文档:查看数据库命令:(1).查看存储过程状态:showprocedurestatus;(2).显示系统变量:show...
- Mysql 8.4数据库安装、新建用户和数据库、表单
-
1、下载MySQL数据库yuminstall-ywgetperlnet-toolslibtirpc#安装wget和perl、net-tools、libtirpcwgethtt...
- mysql8.0新功能介绍
-
MySQL8.0新特性集锦一、默认字符集由latin1变为utf8mb4在8.0版本之前,默认字符集为latin1,utf8指向的是utf8mb3,8.0版本默认字符集为utf8mb4,utf8默...
- 全网最详细解决Windows下Mysql数据库安装后忘记初始root 密码方法
-
一、准备重置root的初始化密码Win+R键启动命令输入窗口;输入cmd打开命令执行窗口;##界面如下##输入命令:netstopmysqld#此操作会停止当前运行的...
- 互联网大厂面试:MySQL使用grant授权后必须flush privilege吗
-
从我上大学时,数据库概论老师就告诉我,MySQL使用grant对用户授权之后,一定记得要用flushprivilege命令刷新缓存,这样才能使赋权命令生效。毕业工作以后,在很多的技术文档上,仍然可以...
- # mysql 8.0 版本无法使用 sqlyog 等图形界面 登录 的解决方法
-
30万以下的理想L6来了##mysql8.0版本无法使用sqlyog等图形界面登录的解决方法当我们在cmd下登录mysql时正常时,用sqlyog等图形界面连接数据库时却...
- MySQL触发器介绍
-
前言:在学习MySQL的过程中,可能你了解过触发器的概念,不清楚各位是否有详细的去学习过触发器,最近看了几篇关于触发器的文档,分享下MySQL触发器相关知识。1.触发器简介触发器即trigg...
- 管理员常用的MySQL命令汇总(一)
-
以下是管理员常用的MySQL命令:以管理员身份连接到MySQL:mysql-uroot-p创建新的MySQL用户:CREATEUSER'username'@'...
- Linux(CentOS) 在线安装MySQL8.0和其他版本,修改root密码
-
一:安装MySQL数据库1),下载并安装MySQL官方的YumRepositorymysql官方仓库地址:https://dev.mysql.com/downloads/repo/yum/选择自...
- 解决 MySQL 8.0 一直拒绝 root 登录问题
-
Accessdeniedforuser'root'@'localhost'(usingpassword:YES)这个错误在网上搜一下,能看到非常多的此类...
- 大模型MCP之MYSQL安装
-
前言学习大模型的时候需要一个mysql,原因还是在公司使用电脑的时候不允许按照Docker-Desktop,我的宿主机其实是MAC,我习惯上还是在centsos上面安装,就发现这件过去很简单的事情居然...
- MySQL ERROR 1396
-
ERROR1396(HY000):OperationCREATEUSERfailedfor'usera'@'%'问题描述mysql>create...
- 一周热门
-
-
Python实现人事自动打卡,再也不会被批评
-
【验证码逆向专栏】vaptcha 手势验证码逆向分析
-
Psutil + Flask + Pyecharts + Bootstrap 开发动态可视化系统监控
-
一个解决支持HTML/CSS/JS网页转PDF(高质量)的终极解决方案
-
再见Swagger UI 国人开源了一款超好用的 API 文档生成框架,真香
-
网页转成pdf文件的经验分享 网页转成pdf文件的经验分享怎么弄
-
C++ std::vector 简介
-
系统C盘清理:微信PC端文件清理,扩大C盘可用空间步骤
-
飞牛OS入门安装遇到问题,如何解决?
-
10款高性能NAS丨双十一必看,轻松搞定虚拟机、Docker、软路由
-
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)