单体工程结构

本文主要说明下单体项目的工程结构如何设计,目前业界存在两种主流的应用工程结构:一种是阿里推出的《Java开发手册》中推荐的,另外一种是基于DDD(领域驱动设计)推荐的。下面我们来看下两种工程结构是怎样的。

一、 基于阿里《Java开发手册》的分层结构

阿里巴巴的官方文档的分层主要是分为如下这些层:

开放API 层:可直接封装Service 接口暴露成RPC 接口;通过Web 封装成http 接口;网关控制层等。
终端显示层:各个端的模板渲染并执行显示的层。当前主要是velocity 渲染,JS 渲染,JSP 渲染,移动端展示等。
Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。
Service 层:相对具体的业务逻辑服务层。
Manager 层:通用业务处理层,它有如下特征:
          1)对第三方平台封装的层,预处理返回结果及转化异常信息,适配上层接口。
           2)对Service 层通用能力的下沉,如缓存方案、中间件通用处理。
           3)与DAO 层交互,对多个DAO 的组合复用。
DAO 层:数据访问层,与底层MySQL、Oracle、Hbase、OB 等进行数据交互。
第三方服务:包括其它部门RPC 服务接口,基础平台,其它公司的HTTP 接口,如淘宝开放平台、支付宝付款服务、高德地图服务等。
外部数据接口:外部(应用)数据存储服务提供的接口,多见于数据迁移场景中。

调用关系如下:

涉及到的领域模型如下:

DO(Data Object):此对象与数据库表结构一一对应,通过DAO 层向上传输数据源对象。
DTO(Data Transfer Object):数据传输对象,Service 或Manager 向外传输的对象。
BO(Business Object):业务对象,可以由Service 层输出的封装业务逻辑的对象。
Query:数据查询对象,各层接收上层的查询请求。注意超过2 个参数的查询封装,禁止使用Map 类来传输。
VO(View Object):显示层对象,通常是Web 向模板渲染引擎层传输的对象

基于这样的规范我创建了一个demo工程的目录,下面我来解释下这个结构



├─src
│  ├─main
│  │  ├─java
│  │  │  └─com
│  │  │      └─demo
│  │  │          ├─client           --第三方服务:调用第三方服务
│  │  │          │  ├─model         --模型对象
│  │  │          │  └─service       --接口
│  │  │          ├─controler        --终端显示层
│  │  │          │  ├─request       --请求对象
│  │  │          │  ├─response      --响应包装对象
│  │  │          │  └─vo            --不同接口显示层对象
│  │  │          ├─dao              --DAO 层
│  │  │          │  ├─config        --数据库的配置文件
│  │  │          │  ├─dbclient      --与底层MySQL、Oracle、Hbase等进行数据交互的文件
│  │  │          │  ├─query         --数据查询对象
│  │  │          │  ├─do            --此对象与数据库表结构一一对应
│  │  │          │  ├─serializer    --序列化相关  
│  │  │          │  ├─sharding      --分库分表类目
│  │  │          │  └─utils         --一些公共类
│  │  │          ├─facede           --开放API 层:对外封装的Service接口暴露成RPC接口
│  │  │          │  ├─constant      --常量
│  │  │          │  ├─model         
│  │  │          │  ├─request       --请求对象
│  │  │          │  └─service       --接口层
│  │  │          ├─job              --开放API 层:处理job工作           
│  │  │          │  └─model         --数据传输对象
│  │  │          ├─manager          --Manager 层
│  │  │          │  └─dto           
│  │  │          ├─mq               --开放API 层:处理mq工作
│  │  │          │  ├─config
│  │  │          │  ├─consumer      --处理消费者工作
│  │  │          │  ├─model
│  │  │          │  └─publish       --处理生产者工作

│  │  │          ├─service          --Service 层
│  │  │             ├─schedule      --处理定时任务
│  │  │          │  ├─bo
│  │  │          │  └─dto
│  │  │          └─web              --Web 层
│  │  │              ├─filter       --过滤层
│  │  │              └─Interceptor  --拦截器层
│  │  └─resources                   --资源文件
│  │      └─META-INF
│  └─test                           --针对每个层次文件的测试文件
│      └─java
│          └─com
│              └─demo
│                  ├─client
│                  │  ├─model
│                  │  └─service
│                  ├─controler
│                  │  ├─request
│                  │  ├─response
│                  │  └─vo
│                  ├─dao
│                  │  ├─config
│                  │  ├─dbclient
│                  │  ├─do
│                  │  ├─query
│                  │  ├─sharding
│                  │  ├─serializer
│                  │  ├─sharding
│                  │  └─utils
│                  ├─facede
│                  │  ├─constant
│                  │  ├─model
│                  │  ├─request
│                  │  └─service
│                  ├─job
│                  │  └─model
│                  ├─manager
│                  │  └─dto
│                  ├─mq
│                  │  ├─config
│                  │  ├─consumer
│                  │  ├─model
│                  │  └─publish

│                  ├─service
│                  │  ├─schedule
│                  │  ├─bo
│                  │  └─dto
│                  └─web
│                      ├─filter
│                      └─Interceptor
└─
 

可能上面的信息比较多看者比较不清晰,下面我们用列表来展示下:

层次

包名

对象名规范

备注

测试层

test

对象名规范同各层级

开放API 层

job、mq、

model

model为模型对象

终端显示层

controler

request、response、vo

Web 层

web

Service层

service

bo、dto

Manager层

manager

dto

DAO层

dao

query、do

第三方服务

client

model

二、 基于DDD(领域驱动设计)的分层结构

DDD(领域驱动设计,Domain-Driven Design)的分层结构主要是为了更好地组织和分离关注点,确保业务逻辑的清晰性和可维护性。DDD 的分层结构通常包括以下几个层次:

  1. 用户接口层(User Interface Layer):
    • 这一层主要负责与前端应用或其他外部服务的交互。
    • 它会接收和响应外部请求,并将业务逻辑的结果展示给用户。
    • 这一层不应该包含任何业务逻辑,主要是数据的展示和接收。
  1. 应用服务层(Application Service Layer):
    • 这一层是DDD中的业务编排层,它协调领域层中的各个组件来执行特定的业务用例。
    • 应用服务层通常包含服务组合、编排、安全认证、权限校验、事务控制等功能。
    • 应用服务层可能会调用多个领域服务来完成一个复杂的业务操作。
  1. 领域层(Domain Layer):
    • 这是DDD中的核心层,包含了业务领域的所有核心逻辑和概念。
    • 领域层主要由实体(Entity)、值对象(Value Object)、领域服务(Domain Service)和领域事件(Domain Event)等组成。
    • 实体和值对象表达了业务概念,而领域服务则实现了复杂的业务规则。
  1. 基础设施层(Infrastructure Layer):
    • 这一层提供了技术实现和支撑服务,如数据库访问、消息传递、缓存等。
    • 基础设施层为上层提供了技术细节的实现,隐藏了底层技术的复杂性。
    • 基础设施层通常实现了领域层中定义的接口和协议,使得上层可以专注于业务逻辑。

DDD的分层结构遵循了依赖倒置原则(Dependency Inversion Principle),即高层模块不应该依赖于低层模块,它们都应该依赖于抽象。此外,DDD的分层结构还强调了领域层的独立性和核心地位,确保业务逻辑的稳定性和可重用性。四个层次调用关系如下:

根据这样的架构我们来理解下和工程结构的映射关系大致如下:

具体到业务流程中是这样的:

基于ddd,我们也可以根据这样的架构来设计一个工程结构,如下:

├─com.company.microservice
├─com.company.microservice
│    │ 
│    ├─apis   API接口层 
│    │    └─controller       控制器,对外提供(Restful)接口
│    │ 
│    ├─application  应用层
│    │    ├─model            数据传输对象模型及其装配器(含校验)
│    │    │    ├─assembler   装配器,,实现模型转换eg. apiModel<=> domainModel
│    │    │    └─dto         模型定义(含校验规则)      
│    │    ├─service          应用服务,非核心服务,跨领域的协作、复杂分页查询等
│    │    ├─task             任务定义,协调领域模型
│    │    ├─listener         事件监听定义
│    │    └─***              others
│    │ 
│    ├─domain   领域层
│    │    ├─common           模块0-公共代码抽取,限于领域层有效  
│    │    ├─module-xxx       模块1-xxx,领域划分的模块,可理解为子域划分     
│    │    ├─module-user      模块2-用户子域(领域划分的模块,可理解为子域划分)
│    │    │    ├─action      行为定义
│    │    │    │    ├─UserDomainService.java        领域服务,用户领域服务
│    │    │    │    ├─UserPermissionChecker.java    其他行为,用户权限检查器
│    │    │    │    ├─WhenUserCreatedEventPublisher.java     领域事件,当用户创建完成时的事件 
│    │    │    ├─model       领域聚合内模型 
│    │    │    │    ├─UserEntity.java                领域实体,有唯一标识的充血模型,如本身的CRUD操作在此处
│    │    │    │    ├─UserDictVObj.java              领域值对象,用户字典kv定义       
│    │    │    |    ├─UserDPO.java                   领域负载对象    
│    │    │    ├─repostiory  领域仓储接口
│    │    │    │    ├─UserRepository.java
│    │    │    ├─reference   领域适配接口
│    │    │    │    ├─UserEmailSenderFacade.java
│    │    │    └─factory     领域工厂  
│    │ 
│    ├─infrastructure  基础设施层
│    │    ├─persistence      持久化机制
│    │    │    ├─converter   持久化模型转换器
│    │    │    ├─po          持久化对象定义 
│    │    │    └─repository.impl  仓储类,持久化接口&实现,可与ORM映射框架结合
│    │    ├─general          通用技术支持,向其他层输出通用服务
│    │    │    ├─config      配置类
│    │    │    ├─toolkit     工具类  
│    │    │    ├─extension   扩展定义  
│    │    │    └─common      基础公共模块等 
│    │    ├─reference        引用层,包装外部接口用,防止穿插到Domain层腐化领域模型等
│    │    │    ├─dto         传输模型定义
│    │    │    ├─converter   传输模型转换器       
│    │    │    └─facade.impl 适配器具体实现,此处的RPC、Http等调用
│    │ 
│    └─resources  
│        ├─statics  静态资源
│        ├─template 系统页面 
│        └─application.yml   全局配置文件

以上就是我对于两种工程结构的阐述,对于两种项目结构,大家要根据自己的项目情况和公司情况进行微调。原因是每种理论都有自己的产生背景、适用条件和使用方法,不能硬搬硬套。而且理论也是有很多变种的,例如ddd也有很多种架构的,例如:洋葱架构、六边形架构等,根据每项架构我们的工程结构肯定还会有一些变种,限于知识的理解不深,本次就不再描述了。ddd我了解的专家是张逸老师,他的著作《解构领域驱动设计》对于ddd的解释是比较全面的,我们做技术的也是基于在一个公司里面做业务,所以工作的上下文中又有了公司和业务者两块,针对这两块,现在的认识是要通过学习togaf这样的企业架构框架和周金根老师的《业务架构解构与实践》这样的著作来深化自己对做好技术工作的理解。

三、两种结构的适用背景

(一)阿里巴巴分层架构

现在对这个结构的认识是比较适用于:

1、在团队还比较小,职责还不是那么清晰的时候,

2、发展变化比较大的业务,因为此时还没有明确的领域概念,团队设置上也没有专人来保证领域的设计;

3、重心在与快速的支撑业务。

(二)ddd分层架构

DDD模式适用于以下几种场景:

1、支持处理复杂业务逻辑场景:当应用程序需要处理复杂的业务逻辑时,DDD可以将业务逻辑封装在领域模型中,从而更好地反映业务需求和业务流程,降低了系统架构的复杂度;

2、多团队协作:当多个团队共同开发一个大型系统时,DDD分层架构可以帮助团队之间更好地协作,每个团队负责不同的领域模型和业务逻辑,减少冲突和重复开发;

3、大型业务需要长期演化并快速迭代和交付的场景:每个子域都可以独立开发、部署和扩展,这样可以使得团队可以快速迭代和交付应用程序

如果将普通的CRUD业务系统也按照这套模式实现,反而会增加系统的复杂度。在现在的认识中,一般中大型的技术团队要能支撑起ddd这样的分层架构,在架构师层面至少有企业架构师、领域架构师(应用架构师)、业务架构师(应用架构师)、技术架构师、基础结构架构师,基础架构架构师有的有会分为、安全架构师、数据架构师其中的几个,但是在团队比较小变化大的业务中,很难支撑这样的团队配置,导致要在做好业务架构设计和时间、人力成本、机会成本、人员职责等产生了矛盾,最终妥协的结构应该就是采取阿里巴巴分层来快速低成本的支持业务跑起来。

参考:DDD-经典四层架构应用_ddd四层架构-CSDN博客、DDD领域驱动设计四、分层架构和代码模型_ddd四种领域模型-CSDN博客、Java应用工程结构 - CN.programmer.Luxh - 博客园 (cnblogs.com)、业务架构 - 知乎 (zhihu.com)、领域驱动设计 - 企业架构设计方法与实践 (tonydeng.github.io)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

生成式 AI - Diffusion 模型的数学原理(3)

来自 论文《 Denoising Diffusion Probabilistic Model》&#xff08;DDPM&#xff09; 论文链接&#xff1a; https://arxiv.org/abs/2006.11239 Hung-yi Lee 课件整理 文章目录 一、图像生成模型本质上的共同目标二、最大似然估计三、和VAE的关联四、概率计算 一、图像生成模…

三维模型优化与可视化开发者服务

一站式服务开发者 1、极速流畅的浏览体验 无需安装插件&#xff0c;实现模型多端展示 最大支持100G模型&#xff0c;杜绝花、卡、闪 2、丰富易用的开发工具 无需掌握图形技术&#xff0c;实现模型轻量化和3D交互展示 提供丰富的SDK和API&#xff0c;简洁易用 老子云API 提供…

Java+SpringBoot:高校竞赛管理新篇章

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

添加环境变量

目录 一、前言二、目的三、添加环境变量的步骤四、检查环境变量是否配置成功 一、前言 在很多地方在下载完软件后都需要添加环境变量方可使用。这里以要在终端使用MySQL为例来说一下&#xff0c;在安装好MySQL8.0版本的前提下&#xff0c;如何添加环境变量。 二、目的 添加环…

力扣OJ题——旋转数组

题目&#xff1a;189.旋转数组 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数 思路一&#xff1a; 1.每次挪动旋转1位&#xff08;用tmp将最后一位存起来&#xff0c;其余所有数据向后移&#xff0c;然后将tmp放在第一个位…

单源最短路径(Dijkstra)

前言 dijkstra&#xff1a;对于无负边的情况下可以达到O(nlogn)且很难被卡 最短路 - OI Wiki (oi-wiki.org) P3371 【模板】单源最短路径&#xff08;弱化版&#xff09; P3371 【模板】单源最短路径&#xff08;弱化版&#xff09; - 洛谷 | 计算机科学教育新生态 (luogu.com…

2.18学习总结

链式前向星的处理和建立 tarjan对割点和缩点的使用 拓扑排序 链式前向星&#xff1a; 预处理&#xff1a; struct edge{int from;int to;int next; }e[N]; int n,m,head[N],dfn[N],low[N],tot,color[N],num[N],out[N],s,instack[N],id; 处理&#xff1a; void add(int …

svg之全局组件,配合雪碧图解决vue2的svg优化问题

这里是vue2中的svg的完整解决方案的另一篇。 <template><svg :class"svgClass"><use :xlink:href"#${name}"></use></svg> </template><script>export default {name: icon,props: {name: {type: String,requi…

lv15 input子系统框架、外设驱动开发 5

一、input子系统基本框架 在我们日常的Linux系统中&#xff0c;存在大量的输入设备&#xff0c;例如按键、鼠标、键盘、触摸屏、摇杆等&#xff0c;他们本身就是字符设备&#xff0c;linux内核将这些字符设备的共同性抽象出来&#xff0c;简化驱动开发建立了一个input子系统。 …

关于Spring Boot应用系统避免因为日切(日期切换)导致请求结果变更的一种解决方案

一、前言 在系统开发过程中&#xff0c;有些业务功能面临日切&#xff08;日期切换&#xff09;问题&#xff0c;比如结息跑批问题&#xff0c;在当前工作日临近24点的时候触发结息&#xff0c;实际交易时间我们预期的是当前时间&#xff0c;但是由于业务执行耗时&#xff0c;…

【EI会议征稿通知】第五届城市工程与管理科学国际会议(ICUEMS 2024)

【Scopus稳定检索】第五届城市工程与管理科学国际会议&#xff08;ICUEMS 2024&#xff09; 2024 5th International Conference on Urban Engineering and Management Science 第五届城市工程与管理科学国际会议&#xff08;ICUEMS 2024&#xff09;将于2024年5月31日-6月2日…

告警能力中台设计与实践(三)——告警通知

一、告警消息与告警通知 1、告警消息 正如笔者在最开始所写的那样&#xff0c;第三方服务通过调用能力中台的OpenAPI实现告警发起&#xff0c;并且每一次的告警请求都会创建、归档为一条告警消息&#xff08;AlarmMsg&#xff09;。 这样的消息是无状态的&#xff0c;并且对…

Python:变量与数据类型

目录 一、变量 1.1 强数据类型与弱数据类型 1.2 全局函数 1.3 变量的命名规范 二、数据类型 2.1 基本数据类型 2.2 复合数据类型&#xff08;引用数据类型&#xff09; 三、数据类型转换 一、变量 变量&#xff1a;顾名思义&#xff0c;变化的量。在python中代指运行时…

【Java面试】MongoDB

目录 1、mongodb是什么&#xff1f;2、mongodb特点什么是NoSQL数据库&#xff1f;NoSQL和RDBMS有什么区别&#xff1f;在哪些情况下使用和不使用NoSQL数据库&#xff1f;NoSQL数据库有哪些类型?启用备份故障恢复需要多久什么是master或primary什么是secondary或slave系列文章版…

【Redis篇】详解布隆过滤器(原理 | 操作 | 代码)

文章目录 &#x1f354;简述布隆过滤器&#x1f33a;原理&#x1f6f8;存入过程&#x1f6f8;查询过程 &#x1f3f3;️‍&#x1f308;优缺点⭐优点⭐缺点 &#x1f339;代码实现&#xff08;本地&#xff09;&#x1f339;代码实现&#xff08;分布式&#xff09; &#x1f3…

Redis 集群(Cluster)

集群概念 Redis 的哨兵模式&#xff0c;提高了系统的可用性&#xff0c;但是正在用来存储数据的还是 master 和 slave 节点&#xff0c;所有的数据都需要存储在单个 master 和 salve 节点中。 如果数据量很大&#xff0c;接近超出了 master / slave 所在机器的物理内存&#…

HTTP请求报文与响应报文格式

HTTP请求报文与响应报文格式 HTTP请求报文与响应报文格式 请求报文包含四部分&#xff1a; a、请求行&#xff1a;包含请求方法、URI、HTTP版本信息b、请求首部字段c、请求内容实体d、空行 响应报文包含四部分&#xff1a; a、状态行&#xff1a;包含HTTP版本、状态码、状态码…

【从Python基础到深度学习】7. 使用scp命令实现主机间通讯

一、生成 SSH 密钥对 ssh-keygen 是一个用于生成 SSH 密钥对的命令行工具&#xff0c;用于身份验证和加密通信 ssh-keygen 二、将本地主机上的 SSH 公钥添加到远程主机 ssh-copy-id 命令用于将本地主机上的 SSH 公钥添加到远程主机上的 authorized_keys 文件中&#xff0c;…

《苍穹外卖》知识梳理P9-定时任务、来单提醒与用户催单

一.定时任务 实现定时任务可以使用spring家族中的sprinig-task&#xff1b; 1.1 spring-task spring-task是Spring框架的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑&#xff1b; 应用场景 信用卡每月归还贷款提醒&#xff0c;定时任务检查&#xff…

Jetpack Compose 第 2 课:布局

点击查看&#xff1a;Jetpack Compose 教程 点击查看&#xff1a;Composetutorial 代码 简介 Jetpack Compose 是用于构建原生 Android 界面的新工具包。它使用更少的代码、强大的工具和直观的 Kotlin API&#xff0c;可以帮助您简化并加快 Android 界面开发。 在本教程中&a…
最新文章