【架构设计】你的应用该如何分层呢?

news2025/1/16 15:55:40

前言

最近review公司的代码,发现现在整个代码层级十分混乱,一个service类的长度甚至达到了5000多行。而且各种分层模型DTO、VO乱用, 最终出现逻辑不清晰、各模块相互依赖、代码扩展性差、改动一处就牵一发而动全身等问题。

我们在吸取了阿里巴巴的分层规范以及网上的一些经验后,重新梳理总结了属于我们项目的分层规范。

三层架构VS四层架构

我们公司原来的分层采用的是传统的三层架构,比如在构建项目的时候,我们通常会建立三个目录:Web、Service 和 Dao,它们分别对应了表现层、逻辑层还有数据访问层。

这样导致一个很大的问题,随着业务越来越复杂,逻辑层也就是service层越来越庞大,所以出现了前面说的5000多行的类,可想而知维护成本有多大。

参照阿里发布的《阿里巴巴 Java 开发手册 v1.4.0(详尽版)》,我们可以将原先的三层架构细化成下面的样子:

  • 终端显示层:各端模板渲染并执行显示的层。当前主要是 Velocity 渲染,JS 渲染, JSP 渲染,移动端展示等。
  • 开放接口层:将 Service 层方法封装成开放接口,同时进行网关安全控制和流量控制等。
  • Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。
  • Service 层:业务逻辑层。
  • Manager 层:通用业务处理层。主要实现下面的功能,1) 对第三方平台封装的层,预处理返回结果及转化异常信息,适配上层接口。2) 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理。3) 与 DAO 层交互,对多个 DAO 的组合复用。
  • DAO 层:数据访问层,与底层 MySQLOracleHbase 等进行数据交互。
  • 外部接口或第三方平台:包括其它部门 RPC 开放接口,基础平台,其它公司的 HTTP 接口。

在这个分层架构中主要增加了 Manager 层,它可以将Service层中的一些通用能力比如操作缓存、消息队列的操作下沉,也可以将通过feign调用其他服务的接口进行一层包装,再提供给Service调用,这也就是所谓的防腐层。

VO、DTO、BO、DO区别

前面讲解了整体的一个分层架构,那么在不同的层级之间必然需要一些模型对象进行流转传递,VO,BO,DO,DTO, 那么他们之间有什么区别呢?

  • VO(View Object):视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。
  • DTO(Data Transfer Object):数据传输对象,用于展示层与服务层之间的数据传输对象。
  • BO(Business Object):业务对象,把业务逻辑封装为一个对象,这个对象可以包括一个或多个其它的对象。
  • DO(Domain Object):领域对象,阿里巴巴规范中引入,此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
  1. VO和DTO什么区别?

VO比较容易混淆的是DTODTO是展示层与服务层之间传递数据的对象,可以这样说,对于绝大部分的应用场景来说,DTOVO的属性值基本是一致的,而且他们通常都是POJO,那么既然有了VO,为什么还需要DTO呢?

例如服务层有一个getUser的方法返回一个系统用户,其中有一个属性是gender(性别),对于服务层来说,它只从语义上定义:1-男性,2-女性,0-未指定,而对于展示层来说,它可能需要用“帅哥”代表男性,用“美女”代表女性,用“秘密”代表未指定。说到这里,可能你还会反驳,在服务层直接就返回“帅哥美女”不就行了吗?对于大部分应用来说,这不是问题,但设想一下,如果需求允许客户可以定制风格,而不同风格对于“性别”的表现方式不一样,又或者这个服务同时供多个客户端使用(不同门户),而不同的客户端对于表现层的要求有所不同,那么,问题就来了。再者,回到设计层面上分析,从职责单一原则来看,服务层只负责业务,与具体的表现形式无关,因此,它返回的DTO,不应该出现与表现形式的耦合。

  1. BO和DTO的区别?

从用途上进行根本的区别,BO是业务对象,DTO是数据传输对象,虽然BO也可以排列组合数据,但它的功能是对内的,但在提供对外接口时,BO对象中的某些属性对象可能用不到或者不方便对外暴露,那么此时DTO只需要在BO的基础上,抽取自己需要的数据,然后对外提供。在这个关系上,通常不会有数据内容的变化,内容变化要么在BO内部业务计算的时候完成,要么在解释VO的时候完成。

我们项目根据实际情况总结了分层领域模型的规范:

  1. 前端传入的参数统一使用DTO接收
  2. 由于公司是TO B项目,只有一个电脑web端,所以返回给展示层或者Feign返回的对象建议直接用DTO返回,特殊情况采用VO返回
  3. 由于历史原因,和数据库模型对应的不采用DO结尾,直接用原始对象,比如学生表student直接使用Student对象
  4. 目前很多代码存在继承关系,比如DTO、VO继承数据库对象,这个坚决不允许

项目目录结构最佳实践

可以参考github上面的github.com/alvinlkk/ma…这个项目,它是一个极度遵守阿里巴巴代码规约的项目。

这里面有个关于Feign设计的亮点, 主要是为了避免服务提供方修改了接口,而调用方没有修改导致异常的问题。

  1. feign接口抽取出一个独立的模块

  1. 服务中依赖feign模块,实现FeignClient

我们来看下整体的一个结构。

mall4cloud
├─mall4cloud-api -- 内网接口
│  ├─mall4cloud-api-auth  -- 授权对内接口
│  ├─mall4cloud-api-biz  -- biz对内接口
│  ├─mall4cloud-api-leaf  -- 美团分布式id生成接口
│  ├─mall4cloud-api-multishop  -- 店铺对内接口
│  ├─mall4cloud-api-order  -- 订单对内接口
│  ├─mall4cloud-api-platform  -- 平台对内接口
│  ├─mall4cloud-api-product  -- 商品对内接口
│  ├─mall4cloud-api-rbac  -- 用户角色权限对内接口
│  ├─mall4cloud-api-search  -- 搜索对内接口
│  └─mall4cloud-api-user  -- 用户对内接口
├─mall4cloud-auth  -- 授权校验模块
├─mall4cloud-biz  -- mall4cloud 业务代码。如图片上传/短信等
├─mall4cloud-common -- 一些公共的方法
│  ├─mall4cloud-common-cache  -- 缓存相关公共代码
│  ├─mall4cloud-common-core  -- 公共模块核心(公共中的公共代码)
│  ├─mall4cloud-common-database  -- 数据库连接相关公共代码
│  ├─mall4cloud-common-order  -- 订单相关公共代码
│  ├─mall4cloud-common-product  -- 商品相关公共代码
│  ├─mall4cloud-common-rocketmq  -- rocketmq相关公共代码
│  └─mall4cloud-common-security  -- 安全相关公共代码
├─mall4cloud-gateway  -- 网关
├─mall4cloud-leaf  -- 基于美团leaf的生成id服务
├─mall4cloud-multishop  -- 商家端
├─mall4cloud-order  -- 订单服务
├─mall4cloud-payment  -- 支付服务
├─mall4cloud-platform  -- 平台端
├─mall4cloud-product  -- 商品服务
├─mall4cloud-rbac  -- 用户角色权限模块
├─mall4cloud-search  -- 搜索模块
└─mall4cloud-user  -- 用户服务
复制代码

结束语

关于应用分层这块我觉得没那么简单,特别是团队大了以后,人员水平参差不齐,很难约束,很容易自由发挥,各写各的。不知道大家有没有什么好的办法呢?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/145138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

spring之aop底层实现

1.aop之ajc增强 什么是ajc增强? ajc是aop的另外一种实现, 通过aspectj编码器来改动class源文件实现aop 2.aop之agent增强 什么是agent增强? agent是aop的另外一种实现,是通过类加载时改动class类 3.aop之proxy增强-jdk代理 …

Mac系统入门之电脑卡死怎么办

当你兴冲冲的从菜鸡驿站提回来一台新的电脑,你欣喜若狂,迫不及待的拆开快递箱,里面是一台苹果电脑,这时,你不禁抓耳挠腮:Mac系统怎么用啊? 下面,这篇专栏教你如何入门Mac系统 https://blog.csdn.net/cyyyyds857/category_12163999.html –––––前言 你正兴致勃勃的写着…

mysql中字符串拼接、填充和切片

一、本文主要结构 在编程过程往往会遇到,多个字符串需要进行拼接或者填充固定值或者截取部分数据,本文主要实战下面四个函数 concat(str1, str2,…):字符串进行拼接 lpap():左边填充 rpad(&…

【C语言】指针经典题分析

🏖️作者:malloc不出对象 ⛺专栏:《初识C语言》 👦个人简介:一名双非本科院校大二在读的科班编程菜鸟,努力编程只为赶上各位大佬的步伐🙈🙈 目录前言一、指针与数组经典题解析二、经…

创新的概念、设计和生产鞋类和鞋类软件丨Jevero及Botcha 3D功能简介

Jevero功能简介 重新定义鞋类发展 Jevero是图案工程师、鞋类开发人员和设计师的优秀支持。从设计到生产都在一个工具中完成。 产品功能及优势 01、更快的开发,缩短上市时间 Jevero使您的图案工程师、鞋类开发人员、工业设计师之间能够进行协作。利用Rhino平台产…

两数相加 java语言

leetcode地址:两数相加描述:给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除…

DevData Talks | 张乐、茹炳晟、应阔浩、任晶磊:研发效能实践的2022年复盘和展望

跌宕起伏的 2022 年已经成为过去时。在这一年,我们既看到外部环境变幻莫测,也看到研发效能行业沉下心来稳步发展,从宏大的概念和价值,转向具体的问题,和务实、可行动的解决方案。 在新一年的开端上回望,20…

靶机测试CyNix笔记

靶机测试CyNix笔记 靶机描述 Level: Intermediate-HardUser flag: user.txtRoot flag: root.txtDescription: It’s a Boot2Root machine. The machine is VirtualBox compatible but can be used in VMWare as well (not tested but it should work). The DHCP will assign …

webpack中模块加载器Loader、插件plugins、optimization属性

目录 模块加载器(Loader) 导入css文件 加载图片 方法一 方法二 转换es6(向下兼容es5) html代码组件导入导出 导入less文件 自定义loader(Markdown文件加载器) markdown-loader.js文件 webpack.c…

【Linux】程序的翻译过程(图示详解)

因为淋过雨,所以懂的为别人撑伞;因为迷茫过,所以懂得为别人指路。 我们都知道写好代码后,编译器会帮助我们把代码生成可执行程序,细加了解又会知道程序的生成又分为四步:预处理、编译、汇编、链接。那么这四…

STM32MP157驱动开发——Linux IIO驱动(上)

STM32MP157驱动开发——Linux IIO驱动(上 )0.前言一、IIO 子系统简介1.iio_dev 结构体2.iio_dev 申请与释放3.iio_dev 注册与注销4.iio_info5.iio_chan_spec二、驱动开发1. ICM20608 的 IIO 驱动框架搭建2.IIO 设备申请与初始化3.基于以上驱动框架开发 I…

[JavaEE初阶] 线程安全问题的原因和解决方案

努力努力,月薪过亿!!! 格局打开~~~ 文章目录前言1. 线程安全问题的概念2. 线程安全问题的原因3. 线程安全问题解决--加锁3. synchronized4. 死锁4.1 产生死锁的情况4.3 产生死锁的必要条件4.4 避免死锁的方法前言 线程安全这里可能会出道面试题,在日常工作中也是很重要的内容.…

MathType公式对齐不正确

MathType公式对齐不正确1.软件环境⚙️2.问题描述🔍3.解决方法🐡4.1.通过标尺对齐4.2.通过输入具体的制表符位置对齐1.软件环境⚙️ Windows10 教育版64位 Word 2021 MathType 7 2.问题描述🔍 在使用Word写论文的时候,总是避免不…

JavaScript 模块:理解模块系统

前言 现代JavaScript开发毋庸置疑会遇到代码量大和广泛使用第三方库的问题。解决这个问题的方案通常需要把代码拆分成很多部分,然后再通过某种方式将它们连接起来。 在ECMAScript 6模块规范出现之前,虽然浏览器原生不支持模块的行为, 但也迫…

ssh连接ubuntu报错

记录问题:1我在本机windows用ssh rootubuntu连接失败 显示端口21啥的2 打开Ubuntu系统,输入ps -e|grep ssh,发现只有agent,没有server3 安装ssh server,输入sudo apt-get install openssh-server,发现报错信…

仅需一个注解,实现 SpringBoot 项目中的隐私数据脱敏!

这两天在整改等保测出的问题,里面有一个“用户信息泄露”的风险项(就是后台系统里用户的一些隐私数据直接明文显示了),其实指的就是要做数据脱敏。数据脱敏:把系统里的一些敏感数据进行加密处理后再返回,达…

一键自动化 | Salesforce发布Automation Anywhere自动化组合!

2022年12月1日,Salesforce推出了一个新的Automation Everywhere Bundle,以加速端到端的工作流编排(Workflow Orchestration)、跨系统自动化,以及在任何地方嵌入数据和AI驱动的工作流。 该捆绑包完全集成到Salesforce F…

acwing第84场周赛(4788,4789,4890)题解

4788. 最大数量 某商场在一天中一共来了 nn 个客人。 每个客人进入商场的具体时刻(精确到分钟)已知。 请你计算并输出在同一时刻(精确到分钟)进入商场的最大客人数量。 输入格式 第一行包含整数 nn。 接下来 nn 行&#xff…

二叉搜索树比起二叉树又有什么不一样呢?

二叉搜索树比起二叉树又有什么不一样呢?🏐什么是二叉搜索树🏐二叉搜索树的实现🏀节点类:🏀构造函数🏀析构函数🏀插入insert⚽非递归版本⚽递归版本🏀查找find⚽非递归版本⚽递归版本…

spring boot 八:SpringBoot响应返回xml数据

spring boot 八&#xff1a;SpringBoot响应返回xml数据 1 前言 根据DispatcherServlet源码分析&#xff0c;研究SpringBoot的Controller返回xml数据的一些方法&#xff0c;包含单独配置和全局配置返回xml数据两种方式。 依赖的SpringBoot版本&#xff1a; <parent>&l…