Java洋葱架构案例

wen java案例 1

本文目录导读:

Java洋葱架构案例

  1. 目录导读
  2. 为什么传统分层架构在微服务时代失效了?
  3. 洋葱架构核心概念:依赖规则与领域模型
  4. Java项目中的洋葱架构落地案例(Spring Boot + MyBatis)
  5. 关键实践:如何隔离基础设施与技术细节
  6. 常见坑与最佳实践(含代码对比)
  7. 问答环节:解决你关于洋葱架构的5个高频问题
  8. 总结:何时该用,何时不该用

Java洋葱架构实战案例:从理论到落地的架构解耦指南

目录导读

  1. 为什么传统分层架构在微服务时代失效了?
  2. 洋葱架构核心概念:依赖规则与领域模型
  3. Java项目中的洋葱架构落地案例(Spring Boot + MyBatis)
  4. 关键实践:如何隔离基础设施与技术细节
  5. 常见坑与最佳实践(含代码对比)
  6. 问答环节:解决你关于洋葱架构的5个高频问题
  7. 何时该用,何时不该用

为什么传统分层架构在微服务时代失效了?

传统三层架构(Controller → Service → DAO)看似清晰,但实际项目中常出现:

  • Service层直接依赖MyBatis的Mapper接口,导致数据库逻辑泄漏到业务层。
  • 一旦更换ORM框架(如从MyBatis换到JPA),Service层代码大面积重写。
  • 单元测试被迫启动Spring容器,因为Service与基础设施强耦合。

核心痛点:依赖方向失控——高层模块(业务规则)没有保护自己不受低层模块(基础设施)变化的影响。

洋葱架构核心概念:依赖规则与领域模型

洋葱架构(Onion Architecture)由Jeffrey Palermo提出,其本质是依赖倒置原则的极致化,结构从内到外:

  • 领域模型(Domain Model):纯Java对象,不依赖任何框架,表达业务状态。
  • 领域服务(Domain Service):编排领域对象,处理复杂业务逻辑。
  • 应用服务(Application Service,又称用例层):定义用例(如“创建订单”),协调领域服务与外部接口。
  • 基础设施(Infrastructure):数据库、消息队列、外部API实现。

铁律依赖只能由外向内(即外圈依赖内圈),内圈绝不依赖外圈,数据库、Spring、MyBatis都是“细节”,必须可以被替换。

Java项目中的洋葱架构落地案例(Spring Boot + MyBatis)

场景:用户下单扣库存系统。

结构示例(基于Maven多模块):

order-domain       (纯Java,无Spring依赖)
order-application  (用例服务,依赖domain接口)
order-infrastructure (实现接口,含MyBatis Repository)
order-interfaces   (Controller层,依赖application)

代码示例

领域层(domain)

public class Order {
    private OrderId id;
    private Money totalAmount;
    // 业务方法:计算折扣
    public Money applyDiscount(DiscountRate rate) { ... }
}

应用层(application)

public class CreateOrderUseCase {
    private final OrderRepository repository; // 接口,定义在domain
    private final InventoryGateway inventory; // 接口,定义在application
    public Order execute(CreateOrderCommand cmd) {
        // 校验、组合领域对象
        Order order = new Order(...);
        boolean reserved = inventory.reserve(cmd.getProductId());
        if (!reserved) throw new BusinessException("库存不足");
        return repository.save(order);
    }
}

基础设施层(infrastructure)

@Repository
public class MyBatisOrderRepository implements OrderRepository {
    private final OrderMapper mapper; // MyBatis接口,仅在该层使用
    @Override
    public Order save(Order order) {
        OrderDO data = OrderConverter.toDO(order); // 转换逻辑仅在此层
        mapper.insert(data);
        return OrderConverter.toDomain(data);
    }
}

关键点OrderRepository接口定义在domain层,而实现藏在infrastructure层,Service层代码根本不知道MyBatis的存在。

关键实践:如何隔离基础设施与技术细节

  • 接口所有权:接口(如OrderRepository)属于内圈(domain),不属于外圈(infrastructure),这样内圈定义行为,外圈实现细节。
  • 使用适配器模式:例如UserJpaAdapter实现UserPort接口,适配JPA或者MyBatis查询。
  • DTO与DO分离:领域对象(Order)与数据对象(OrderDO)拆分,禁止在应用层直接操作OrderDO
  • 依赖注入方向:Spring仅在infrastructureinterfaces层使用,domain与application层保持纯POJO。

常见坑与最佳实践(含代码对比)

❌ 错误示范

@Service
public class OrderService {
    @Autowired
    private OrderMapper mapper; // 直接依赖外部ORM
    public void create(OrderDTO dto) {
        OrderDO data = new OrderDO();
        // 大量setter,业务逻辑和持久化混淆
        mapper.insert(data);
    }
}

✅ 正确示范

@Service
public class OrderApplicationService {
    private final CreateOrderUseCase useCase;
    public OrderApplicationService(CreateOrderUseCase useCase) {
        this.useCase = useCase;
    }
    // 仅做参数转换,无业务逻辑
}

最佳实践清单

  1. 保持领域层纯净:不引入javax.persistenceorg.springframework.stereotype注解。
  2. 用例粒度:每个用例一个类(如CreateOrderUseCase),避免服务类爆炸。
  3. 测试策略:domain和application层用JUnit纯单元测试,不启动Spring。
  4. 包结构映射:使用import控制依赖方向,必要时用ArchUnit测试强制依赖规则。

问答环节:解决你关于洋葱架构的5个高频问题

Q1:洋葱架构和六边形架构(端口-适配器)有什么区别? A:两者本质相同,六边形架构更强调“端口”(输入/输出),洋葱架构更强调层级和领域模型为核心,实践中常混用,核心都是依赖倒置。

Q2:我们团队刚转型,迁移成本高吗? A:短期有成本(重写Repository接口),但长期收益大,建议从新模块开始试点,老模块逐步抽取接口。

Q3:MyBatis的@Param注解放在domain层接口里会怎样? A:不推荐,domain层接口应使用领域原语(如OrderId),@Param属于MyBatis技术细节,应放在infrastructure层实现里。

Q4:是否所有项目都适合洋葱架构? A:不是,对于CRUD极简单的项目(无复杂业务逻辑),洋葱架构会增加类数量,适合业务规则复杂、需要长期演进的中大型系统。

Q5:Controller层属于哪一圈? A:属于最外层(interfaces/UI层),它只负责HTTP协议解析,调用application层用例,不做任何业务判断。

何时该用,何时不该用

该用

  • 业务规则复杂(如金融、电商订单、计费引擎)。
  • 需要替换ORM、消息中间件等基础设施。
  • 团队希望实现高质量单元测试(不启动Spring)。

不该用

  • 单纯的数据展示后台(增删改查无逻辑)。
  • 快速原型验证(MVP阶段)。
  • 团队对DDD和依赖倒置不熟悉时,强推会适得其反。

洋葱架构不是银弹,但它能帮你保护核心业务资产,关键是在“内聚领域”与“技术解耦”之间找到平衡点,建议从Order这样的核心用例开始重构,逐步感受架构带来的秩序感。

抱歉,评论功能暂时关闭!