一、为什么需要调整分层架构
微服务架构最大的特点就是每个服务可以独立开发、独立部署。但传统的DDD(领域驱动设计)分层架构在设计时,更多考虑的是单体应用的整体性。当我们将DDD应用到微服务中时,会发现一些问题:
- 依赖过重:传统分层架构里,基础设施层可能包含数据库、缓存、消息队列等,如果某个服务只想用缓存,却不得不引入整个基础设施层。
- 部署耦合:如果领域层和基础设施层绑定太紧,每次数据库变更都可能影响领域逻辑,导致服务无法真正独立部署。
- 团队协作问题:微服务通常由不同团队维护,如果分层不清晰,团队之间容易在代码耦合上产生冲突。
举个例子:
// 技术栈:Java + Spring Boot
// 传统DDD分层结构(问题示例)
// 领域层直接依赖具体数据库实现(违反依赖倒置原则)
public class OrderService {
@Autowired
private OrderJpaRepository orderRepository; // 直接依赖JPA实现
public void createOrder(Order order) {
// 业务逻辑与数据库操作混杂
if (order.isValid()) {
orderRepository.save(order);
}
}
}
注释:这里领域服务直接依赖了JPA的具体实现,如果换成MongoDB就需要修改领域代码,无法独立部署。
二、调整策略:依赖倒置与适配层
解决上述问题的核心是依赖倒置——让高层模块(领域层)不依赖低层模块(基础设施),而是让低层模块适配高层模块。具体做法:
1. 提取领域接口
在领域层定义仓储接口,基础设施层负责实现:
// 领域层定义接口(不依赖具体实现)
public interface OrderRepository {
void save(Order order);
}
// 基础设施层提供实现(可以是MySQL、Redis等)
@Repository
public class OrderJpaRepositoryImpl implements OrderRepository {
@Override
public void save(Order order) {
// 具体数据库操作
}
}
2. 增加防腐层(ACL)
当微服务之间需要调用时,通过防腐层隔离外部服务的变化:
// 技术栈:Java + Feign
// 防腐层示例:将外部服务"翻译"成领域理解的模型
public class PaymentServiceAdapter {
@Autowired
private PaymentFeignClient paymentClient;
public PaymentStatus queryPayment(String orderId) {
// 将Feign返回的DTO转换为领域模型
PaymentDto dto = paymentClient.getPayment(orderId);
return PaymentStatus.of(dto.getCode());
}
}
注释:即使支付服务接口变更,只需修改适配层,领域逻辑不受影响。
三、实战:可独立部署的分层设计
以一个订单服务为例,展示完整调整后的结构:
// 技术栈:Java + Spring Boot
// 调整后的分层架构
// 1. 领域层(核心业务)
public class Order {
private String id;
private BigDecimal amount;
// 领域方法
public boolean isValid() {
return amount.compareTo(BigDecimal.ZERO) > 0;
}
}
// 2. 应用层(协调领域对象)
public class OrderAppService {
private final OrderRepository orderRepo;
public void createOrder(OrderCommand command) {
Order order = new Order(command.getAmount());
if (order.isValid()) {
orderRepo.save(order); // 依赖抽象接口
}
}
}
// 3. 基础设施层(实现细节)
@Repository
public class OrderMongoRepository implements OrderRepository {
@Override
public void save(Order order) {
// MongoDB具体操作
}
}
关键点:
- 领域层完全不知道数据如何存储
- 切换数据库只需替换基础设施实现
- 应用层通过依赖注入绑定接口与实现
四、注意事项与最佳实践
- 接口归属权:领域接口(如
OrderRepository)必须由领域层定义,而非基础设施层。 - 依赖方向:确保所有依赖箭头指向领域层(如下图示意):
基础设施 → 应用层 → 领域层 ↘___________↗ - 测试策略:
- 领域层用单元测试,不启动Spring容器
- 基础设施层用集成测试
- 团队约定:严格禁止跨层直接调用(如基础设施层直接访问领域模型)。
五、总结
调整后的分层架构让微服务真正具备:
- 技术异构性:每个服务可自由选择数据库、框架
- 独立部署能力:修改数据库不影响领域代码
- 清晰边界:团队协作时减少“踩坑”概率
就像乐高积木,标准化接口是连接块,具体实现是不同颜色的积木。只要接口不变,内部可以随意替换——这才是微服务想要的灵活性。
评论