找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

619

积分

0

好友

75

主题
发表于 5 天前 | 查看: 20| 回复: 0

1、背景

说起应用分层,很多人可能觉得这不就是简单的 Controller、Service、Mapper 三层吗?看似简单,但不少开发者在实际编码中并未清晰划分各层职责。常见的情况是 Controller 里堆满了业务逻辑,而 Service 层却沦为简单的透传工具。功能虽能实现,但代码放置随意,长此以往会导致代码复用困难、层级关系混乱,给后续维护埋下隐患。

在一些开发者眼中,分层可能只是一种形式上的模仿——“前辈这么写,其他项目这么写,那我也这么写”。然而,在真实的团队协作中,每个人的编码习惯各异。有人习惯在 Controller 里处理大量业务,有人则喜欢在 Service 层直接调用远程服务。这种差异会导致代码风格迥异,当后来者需要修改时,就会面临选择困境:是按自己的习惯改,还是遵循已有的“非标准”结构?一旦选择不当,代码的可维护性将进一步恶化。

因此,一套优秀且被团队共识的应用分层,应当具备以下几个关键点:

  • 便于后续代码的维护与扩展;
  • 分层规则需被整个团队接受并遵守;
  • 各层之间的职责边界必须清晰明确。

2、如何进行分层

2.1、阿里规范

在阿里巴巴的Java开发手册中,推荐的应用分层如下:

典型分层架构模型

  • 开放接口层: 可直接封装 Service 方法暴露成 RPC 接口;通过 Web 封装成 HTTP 接口;进行网关安全控制、流量控制等。
  • 终端显示层: 各个端的模板渲染并执行显示的层。当前主要是 velocity 渲染,JS 渲染, JSP 渲染,移动端展示等。
  • Web 层: 主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。
  • Service 层: 相对具体的业务逻辑服务层。
  • Manager 层: 通用业务处理层,它有如下特征:
    1. 对第三方平台封装的层,预处理返回结果及转化异常信息;
    2. 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理
    3. 与 DAO 层交互,对多个 DAO 的组合复用。
  • DAO 层数据访问层,与底层 MySQL、Oracle、Hbase 进行数据交互。

阿里巴巴的规约分层清晰明了,但描述相对概要,导致很多同学对 Service 层和 Manager 层的区别感到模糊,不少项目中因此缺失了 Manager 层。下面我们结合具体业务场景,探讨更优化的分层实践。

2.2、优化分层

基于实际业务开发经验,我们总结了一个更为理想的分层架构模型。需要说明的是,由于示例中 RPC 框架选用的是 Thrift,相比 Dubbo 等框架会多出一层(TService),其作用与 Controller 层类似。

包含Thrift调用的优化分层架构图

  • 最上层 Controller 和 TService: 对应阿里规范中的开放接口层/Web层。其职责应是轻业务逻辑、参数校验、异常兜底。通常这类接口可以较容易地更换协议类型,因此业务逻辑必须轻量,甚至不包含具体逻辑。
  • Service 层业务逻辑层,复用性较低。这里推荐每一个 Controller 方法都对应一个 Service 方法。切勿将业务编排放在 Controller 层。为什么呢?如果业务编排在 Controller 中,当我们需要新增 Thrift 接口时,同样的编排逻辑就得在 TService 里重写一遍,造成代码复制,如下图所示:

业务逻辑放Controller层导致代码重复

这种重复劳动会严重降低开发效率。因此,我们必须将业务编排逻辑都收拢到 Service 层中:

业务逻辑收拢至Service层实现复用

  • Manager 层可复用逻辑层。这里的 Manager 可以是单一服务的封装,例如 CacheManager、MQManager;也可以是复合逻辑的封装,当你需要协调多个 Manager 时(如逻辑上的连表查询),可以聚合为一个 Manager。如果是 HttpManager 或 RpcManager,通常需要在这一层进行数据格式的转换。
  • DAO 层数据库访问层。其核心职责是“操作数据库的某张表,并映射到某个 Java 对象”。DAO 应只允许自己所属的 Service 访问,其他 Service 若要访问该数据,必须通过对应的 Service 层。

3、分层领域模型的转换

在阿里巴巴编码规约中,定义了以下几种领域模型:

  • DO(Data Object): 与数据库表结构一一对应,通过 DAO 层向上传输的数据源对象。
  • DTO(Data Transfer Object): 数据传输对象,Service 或 Manager 向外传输的对象。
  • BO(Business Object): 业务对象。由 Service 层输出的封装业务逻辑的对象。
  • AO(Application Object): 应用对象。在 Web 层与 Service 层之间抽象的复用对象模型,极为贴近展示层,复用度不高。
  • VO(View Object): 显示层对象,通常是 Web 向模板渲染引擎层传输的对象。
  • Query: 数据查询对象,各层接收上层的查询请求。注意超过2个参数的查询应封装,禁止使用 Map 类来传输。

分层领域模型流转示意图

理论上,每一层都应有自己对应的领域模型。但若机械地照此执行,一次请求/响应流程中,一个对象可能经历三到四次转换,大量代码将耗费在无休止的对象映射上,开发效率极低。

因此,我们需要采取一个更务实的折中方案:

  1. 允许 Service / Manager 层操作 DO 数据领域模型。因为这两个层级本身的工作就是业务逻辑处理和数据组装。
  2. 禁止 Controller / TService 层的领域模型传入 DAO 层,这违背了职责划分原则。
  3. 同理,也禁止 DAO 层的数据直接传入 Controller / TService 层。

4、总结

总的来说,清晰合理的业务分层是代码规范的重要组成部分,它直接决定了代码未来的可复用性、职责清晰度和边界明确定义。当然,分层模式见仁见智,不同团队的习惯也可能不同,很难制定一个放之四海而皆准的绝对标准。但只要能够满足职责逻辑清晰、后续维护容易这两个核心目标,就是好的分层实践。

希望本文的探讨能对你和你的团队有所启发。如果你想深入学习更多关于系统设计、架构原理和Java生态的最佳实践,欢迎访问云栈社区与广大开发者交流探讨。




上一篇:恶意Chrome扩展窃取90万用户数据,仿冒AI工具窃取ChatGPT与DeepSeek聊天记录
下一篇:NVIDIA协同设计如何重构AI工厂:从芯片性能到Token效率的系统标准
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-24 02:49 , Processed in 0.367920 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表