单应用多系统设计

“单应用”的概念其实是相对于”微服务“来讲的。“微服务”项目往往单个服务逻辑比较简单,不会有过于复杂的代码设计。本文使用 Focus聚焦社区 项目作为示例,主要介绍如何使用GoFrame开发框架设计包含多个系统的”单应用“项目。在开始之前,建议您先了解一下GoFrame对于开发业务型项目的一些基础设计介绍:

本文是介绍的单应用下多系统的复杂设计,如果您对此比较感兴趣,欢迎往下阅读。如果您主要接触的微服务开发场景,可选择忽略,后续会有其他的设计文章对微服务工程这块做专门的介绍。

一、项目结构

包含多个系统的单应用目录结构会不太一样,主要由于不同的系统有不同的功能逻辑,也有相同的功能逻辑。我们需要将不同的功能逻辑充分地进行解耦,互不干扰;而相同的功能抽离出来,便于复用。还是高内聚,低耦合思想。

├── app │ ├── dao │ ├── model │ ├── shared │ └── system │ ├── admin │ │ └── internal │ └── index │ └── internal │ ├── api │ ├── define │ └── service ├── config ├── document ├── library ├── packed ├── public ├── template ├── upload ├── Dockerfile ├── go.mod └── main.go 目录/文件名称| 说明| 描述 ---|---|--- app| 业务逻辑层| 所有的业务逻辑存放目录。 - dao| 数据访问| 数据库的访问操作,仅包含最基础的数据库CURD方法。 - model| 结构模型| 数据相关的实体结构定义,以及一些系统间通用的数据结构定义。 - shared| 通用逻辑| 多系统间可复用的、通用的service功能逻辑。 - system| 系统模块| 内部可能包含多个子系统,不同子系统之间资源相互隔离。 - index| 前端页面| 子系统,前端页面。该名称index仅作示例。 - internal| 内部模块| 系统内部模块,仅供当前内部系统调用,无法在系统间共享。 - api| 业务接口| 当前系统内部接收/解析用户输入参数的入口/接口层 - define| 结构定义| 当前系统内部的输入、输出数据结构定义。 - service| 逻辑封装| 当前系统内部业务逻辑封装,实现特定的业务需求。 config| 配置管理| 所有的配置文件存放目录。 docker| 镜像文件| Docker镜像相关依赖文件,脚本文件等等。 document| 项目文档| Documentation项目文档,如: 设计文档、帮助文档等等。 library| 公共库包| 公共的功能封装包,往往不包含业务需求实现。 packed| 打包目录| 资源文件打包的Go文件存放在这里,boot包初始化时自动调用。 public| 静态目录| 仅有该目录下的文件才能对外提供静态服务访问。 template| 模板文件| 模板文件存放的目录。仅当需要使用模板引擎的场景下有用。 Dockerfile| 镜像描述| 云原生时代用于编译生成Docker镜像的描述文件。 go.mod| 依赖管理| 使用Go Module包管理的依赖描述文件。 main.go| 入口文件| 程序入口文件。

可以看到,基本的项目结构和GoFrame官方提供的基础项目结构差别不大,主要在app目录下的目录结构有一些差别。比较常见的单应用多系统是这样的:一个前台系统,一个后台系统。例如:

单应用多系统设计 - 图1

图1. 单应用多系统项目结构

二、复用模块

数据访问 - dao

可以看到处于外层的dao和model都是可被多个业务系统复用,这应该能够很好理解,这两块本身就是耦合最低的功能模块。dao模块负责数据访问管理,对于整个应用来讲,数据是通用的,可以被多个业务系统访问。

通用结构 - model

但是需要注意的是,此时的model中仅包含通用的数据结构定义,例如数据库实体对象定义、共享数据结构定义。例如,以下图例model中的captcha、context、view都是共享数据结构;而其他的模块均是数据库实体数据结构封装。

单应用多系统设计 - 图2

图2. 可复用model通用数据结构模块

通用逻辑 - shared

shared模块存放的是多系统间可复用的service功能逻辑,由于service这个名称被使用到业务系统中,因此外部相同职责的模块名称尽量不要重复冲突以便更好维护,所以叫做shared。在下图的示例中,可以看到,我们整个单应用中,多个系统间共用了context上下文的功能逻辑。

单应用多系统设计 - 图3

图3. 可复用的shared功能逻辑

三、业务系统

在这个示例中,包含了两个业务系统index前台系统和admin后台系统,两个业务系统在代码设计上相互独立,没有耦合。可以看到,每个业务系统内部都使用internal包将自身的业务逻辑包含了起来,目的是使得内部的功能模块不对外公开,使得整个项目在模块引用的时候更加简洁。

单应用多系统设计 - 图4

图4. 多业务系统代码结构示例

每个业务系统下均有api、define、service三层代码模块,每个模块均负责当前业务系统下对应的职责管理。

业务接口 - api

api模块负责当前业务系统的请求输入与输出,包括对输入参数的过滤、转换、校验,对输出数据结构的维护,并调用service实现业务逻辑处理。

结构定义 - define

define模块负责当前业务系统的数据结构定义,包括自定义的数据对象、输入输出数据结构等定义,其功能类似于GoFrame项目结构中的model,但是不包含数据库实体对象数据结构定义,而数据库实体对象数据结构定义由外层的model负责。

业务逻辑 - service

service模块负责当前业务系统的业务逻辑实现以及功能封装。

系统初始化

可以看到我们整个项目结构中,已经不存在GoFrame框架项目结构推荐的boot与router模块。因为在多系统并存的情况下,无法执行统一的初始化和路由注册,初始化和路由注册交给各个业务系统自行维护,这样的目的也是为了尽可能地实现低耦合设计。例如,前台系统的初始化即路由注册在这里管理:

单应用多系统设计 - 图5

图5. 业务系统初始化即路由注册

四、应用初始化

应用初始化主要负责一些通用的初始化设置,并调用各个业务系统的初始化方法实现系统的初始化。随后启动应用。

单应用多系统设计 - 图6

图6. 应用初始化即启用

Content Menu