Spring Cloud全家桶用了挺长时间了,很长一段时间都是基于已有的架构进行需求研发。今年成为团队技术负责人,承担了新的项目,这是很好的一个机会,于是开启了项目架构升级之路。
架构,是团队项目的根基。在一个团队内通过规定一个固定的架构设计,可以让团队内能力参差不齐的同学们都能有一个统一的开发规范,降低沟通成本,提升效率和代码质量。
本篇博客将以项目架构熟悉使用-学习接触新的架构设计-新项目新架构为思路,记录一下自己在项目架构设计方面的成长。
其实之前对Spring Cloud仅停留在自己的了解,还没有真正的实战经验,刚看到项目框架,整体上看是比较简单的,项目都是由固定的三个模块组成,结构如下:
下面具体描述一下每个模块所包含的包及作用:
web模块
1)依赖api模块,提供前端接口。
2)在controller层代码中,调用feign client包下的feign接口。
3)nacos config包下均是需要通过nacos配置获取得到的属性等。core包下主要是aop日志记录和异常捕获。
provider模块
1)依赖api模块,实现feign接口。
2)feign client包主要是调用其他服务的feign接口。
3)dao和service实现包是对数据库进行操作数据库访问层和逻辑处理层。
4)nacos config包同样是需要通过nacos配置获取属性定义的各个类。
api模块
1)feign接口,即服务与服务之间的调用接口定义。
2)entity和service interface是数据库实体与service接口定义。
3)dto包下是所有feign接口的入参和出参类定义。
4)vo包下是前端web模块入参和出参类定义。
以上项目架构,从过去一段时间的使用体会来说,其实对于熟悉项目框架的研发人员来说代码的编写是不可控的,对于不熟悉了项目框架的研发人员来说是不太友好的。这里列举几个明显的弊端:
很长一段时间,我都是基于以上架构做需求开发,也是因为改变不了,所以只能是接受使用。今年机会来了,我独立带了一个新的项目团队,该团队有新项目也有旧项目,新项目勾起了我的改变欲望,于是就开始了下面的新架构设计之路。
如上图所示,洋葱架构是由多个同心层构成,它们相互连接,并朝向代表领域的核心。
依赖性
圆圈代表不同的责任层。一般来说,潜入得越深,就越接近于领域和业务规则。外圈代表机制,内圈代表核心领域逻辑。外层依赖于内层,而内层则对外圈一无所知。通常情况下,属于外圈的类、方法、变量和源代码依赖于内圈,但是反过来也一样。
数据格式/结构可能因层而异。外层的数据格式不应该被内层使用。例如,API 中使用的数据格式可以与 DB 中用于持久化的数据格式不同。数据流可以使用数据传输对象。每当数据跨层/跨界时,它应该以方便该层的形式出现。例如,API 可以有 DTO,DB 层可以有 Entity Objects,这取决于存储在数据库中的对象与领域模型的不同。
数据封装
每个层/圈封装或隐藏内部的实现细节,并向外层公开接口。所有的层也需要提供便于内层消费的信息。其目的是最小化层与层之间的耦合,最大化跨层垂直切面内的耦合。
关注点的分离
应用被分为若干层,每一层都有一组职责,并解决不同的关注点。每一层都作为应用中的模块/包/命名空间。
耦合性
低耦合性,可以使一个模块与另一个模块交互,而不需要关注另一个模块的内部。所有的内部层都不需要关注外部层的内部实现。
其实自己一开始并没有了解过“洋葱架构”,而是在其他项目组重构的时候听说而来,所以不忙的时候就会看看关注一下。通过对架构思想的了解,从github上看过了很多的项目示例,在新项目开始前,也有充足的时间让我去做准备。接下来的架构升级就是将学习到的架构设计与自身项目实际相结合的成果。
新项目整体架构设计如下图所示:
原来的三个模块转变为六个模块,这也不是凭空想象而来,而是依据项目实际情况拆分的,主要是为了避免旧架构的一些明显缺陷,每个模块都是有着明确的职责。
type模块
前端接口的请求参数和返回参数,属于独立模块,仅对参数做一些校验功能,类的命名也不用再加VO标识。
client模块
spring cloud feign client统一定义模块,web模块调用feign client接口使用。在web模块中加了一层service也是为了对于不同的类需要用到的feign client可以在这一层统一处理,provider模块中不再定义feign client。
infrastructure模块
与数据库操作相关的所有类均存在于该模块中,并且不会对外暴露,只供自身项目的provider模块使用。
web模块
1)提供前端接口的模块,但不再依赖api模块。直接通过依赖feign client模块,调用服务的feign接口。
2)依赖types模块,直接提供接口的入参和出参。
provider模块
1)依赖api模块,实现feign接口。
2)依赖infrastructure模块,实现对数据库的操作。
api模块
1)feign接口,即服务与服务之间的调用接口定义。
2)dto包下是所有feign接口的入参和出参类定义。
前三个模块是新加的模块,后三个模块与之前的设计相比也有不同的作用,这改变了过去架构混乱各模块职责不清的弊端,降低了各模块的耦合程度,从实际使用来看,新成员的加入很容易理解和上手,也提升了代码可读性与健壮性。
目前,团队中部分新项目采用的是升级后的架构,但也不是所有项目都采用的该架构。由于不同项目有着业务与职责的差异,也是在不同的项目中会根据实际情况做调整。
正如之前看到过文章里说的那样,实际使用中“洋葱架构”的每一层我们并不一定都是需要的,而应该根据项目实际情况做动态设计和调整。这一次的架构使用——学习——升级对自己来说算是一次很好地成长。