简述
前情回顾
在前面的章节中,我们陆续介绍了环境准备的各个工具的安装,这就好比我们古语常言的“磨刀不误砍柴工”。那接下来的这个章节,我们将开始介绍项目结构的搭建以及其中应该注意的一些事项。
常见的构建工具介绍
由于本系列是基于Java生态来构建的体系结构,构建的工具也以介绍Java生态的为主。
在Java生态里面,构建项目一般有Ant, Maven, Gradle.
Ant
相信有10年以上工作经验的同学对Ant会比较了解。
在使用Ant开始一个新的项目时,首先应该编写Ant构建文件。构建文件定义了构建过程,并被团队开发中每个人使用。Ant构建文件默认名为build.xml,也可以取其他的名字。只不过在运行的时候 把这个命名当作参数传给Ant。构建文件可以放在任何的位置。一般做法是放在项目顶层目录中。 这样可以保持项目的简洁和清晰。下面是一个典型的项目层次结构。
(1) src存放文件。
(2) class存放编译后的文件。
(3) lib存放第三方JAR包。
(4) dist存放打包,发布以后的代码。
Ant需要自行在网上查找项目所用到的Jar包,并下载放置在lib目录下,这个是其最大的弊端吧。
本人也有将近八、九年没有再用过Ant了,所以在本系列中不再推荐了。
Maven
提起Maven,Java生态圈的各位同学应该比较了解了。引用官方的解释,Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件。
Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性,所以常常用两三行 Maven 构建脚本就可以构建简单的项目。由于 Maven 的面向项目的方法,许多 Apache Jakarta 项目发文时使用 Maven,而且公司项目采用 Maven 的比例在持续增长。
说到这里,我们再回头看看Ant,来品品两者之间的些许区别。
Ant 可以说主要是为了 Java 技术开发项目提供跨平台的构建任务。而Maven从 Ant 借用了绝大多数构建任务,但Maven又不仅仅只是构建,更多的是描述项目的高级方面的一些管控。它包含了一个项目对象模型 (Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),和用来运行定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑。当我们在使用Maven的时候,会用一个明确定义的项目对象模型来描述我们的项目,然后Maven可以应用横切的逻辑,这些逻辑来自一组共享的(或者自定义的)插件。
Gradle
当当当当,随着时间的推移,这几年又出了一个工具大神Gradle。继续沿用官方的说法,Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建开源工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。
面向Java应用为主。当前其支持的语言限于Java、Groovy、Kotlin和Scala,计划未来将支持更多的语言。
总体来说,各个工具算是迭代更新吧,不过对于本人来说三种工具都用过,现在的应用主要还是以Maven为主,新起的项目可能会用Gradle,Ant已基本不用了。在本系列中将以Maven为主来介绍。
常见结构树介绍
说起项目的结构,刨除传统的巨石结构,现在的不论SOA还是微服务,基本都是由多个子项目(子服务)构成。
- 情况1:如果一个比较大的项目,下分多个子项目,每个项目由不同的团队来完成,项目之间除了定义接口之外,并不关注彼此的实现,对于这种情况,项目之间一般没有太多的关联(接口除外),每个项目组可以自由选择自己所负责项目的技术栈(可以是Java,Go,Python等等), 每个子项目可以定义自己内部的项目结构,可以由一个或者多个子服务组成,子项目内部建议使用统一的项目结构树。
- 情况2:如果一个项目,即使下分了多个子项目或者子服务,但是这些都是由一个团队来完成,技术栈是同一套,这种情况一般情况下会构建统一的项目结构树。
- 情况3:如果一个项目是由一个团队来完成,技术栈也是一套,考虑到技术选型,也会有每个服务来维护自己服务的情况,但是这种情况不太推荐,会凭白增加后续维护的工作量,大家开发的过程中也可能会遇到各种无谓的一些问题。
我们在本文中,主要阐述的是单个Team内的一个项目的结构树,对于跨Team的项目,其实每个Team维护自己的即可,统一了反而会出现一些问题。
单个Team内的一个项目的项目结构一般会有两种形式来组织:一个是扁平结构,一个是树状结构。
扁平结构
扁平的项目结构,一般常见于业务模块的服务之间相互直接依赖(或Restful接口或者RPC)。其结构树一般如下:
image.png
其实目前,无论哪种微服务体系结构,此种方式的项目结构都不是很常见。
树状结构
树状结构的定义一般会遵循下面的几个不成文的规则:
- POM一般分为层级节点和项目(服务)节点。
- 层级节点一般有:根POM,以及根下面每个项目子项目的子根POM。如果需要还可以再加一层。一般推荐3层即可,太深的话不太容易管理。
- 服务节点一般是单个微服务的节点,或者单个lib包的节点。
而树状结构,由于微服务的技术实现不同,树状结构的构成也会有所不同,其中以Dubbo的RPC框架和Spring Cloud的Restful框架最为典型。
Dubbo型结构树
由于现在所在的公司采用的是Dubbo,并且最初始的架构据说是阿里当时搞Dubbo的核心架构师来指导搭建的,在这里也给大家稍微分享下该树形结构的做法。
- 根POM一般用来定义子项目(服务)的Module。有些公司或者项目也会在跟POM对该项目所引用的包进行统一版本约束和管控。
- 子一层为单个业务服务模块的根POM。该层的主要作用也是用来定义该项目(服务)下的Java项目的子模块(亦即Module)。
- 子二层即为服务的实际项目代码层。
对于子二层的划分,一般又会遵循:
- 单个Facade项目。一般用来封装本服务的RPC接口,以及接口中所用到的本服务的Java Bean。该项目会被编译为lib包供其它调用本本服务的服务使用。
- 单个Core项目。一般用来实现Facade所定义的接口以及本服务的业务逻辑,包括Service以及Dao层。
- 一个或者多个Distribution项目。Distribution即是来打包Facade和Core的发布包,一般该服务的Controller会定义在本项目中。讲到这里大家可能会有疑惑了,那为什么会有多个Distribution。其实多个Distribution,你可以为你的Controller也好或者RPC也好,按照实际业务需求进行拆分,例如:读写分离就可以通过这样来实现(读写分离其中一种哈,还有中间件的模式等)。
额外说一点个人的看法,这个结构其实只是阿里Dubbo团队比较推荐的一种方式,大家可以在自己的项目中灵活运用,如果该项目都是由一个团队来完成的,大家都在一个技术栈里面,其实我更多的是建议把Facade这一层给统一合并了,如果不需要多Distribution的话,也把Core直接和Distribution合并了,这样就变成扁平结构了,oh MGD,忽然觉得扁平结构是不是就是这么来的,嘿嘿,开个玩笑。
总之,公说公有理婆说婆有理,各自不同的看法而已,没有绝对的对与错,适合自己的才是正确的,仅供参考。
Spring Cloud型结构树
说完了Dubbo的结构树,那我们再来看看Spring Cloud体系结构比较推荐的结构树。
一方面来说,Spring Cloud的通讯协议采用基于HTTP的Restful风格的数据传输,这就决定了,在Spring Cloud微服务体系结构里面,我们不需要定义类似于Dubbo里面的RPC的Facade,我们这是定义好Restful所运用的接口的Java Bean即可。
另一方面来说,Spring Cloud有着自己丰富的组件支持(Dubbo现在也有了部分组件了哈,具体可以参考Dubbo的Apache官网),这些项目我们也要在Spring Cloud运行期间跑起来,所以我们在规划基于Spring Cloud的项目结构树的时候,要把这块儿也统一考虑起来。
综合起来说:
- 根POM还是需要滴。
- Spring Cloud组件服务层子POM。
- 公共组件层子POM。
- API层子POM。
- Composite组合层子POM。
-
Core层子POM。
抛开SpringCloud的组件层,我们先说说,划分API,Composite和Core的用意。
image.png
这个图是我两年前绘制的,其实下面还跟着两段英文。在这里就不跟大家献丑了,直接中文描述了。
层次划分的因由,主要有下文描述。
Edge Server
在Spring Cloud1.0中,由Zuul来充当,在Spring Cloud2.0中,Spring Cloud团队自己搞了一个基于Netty的非阻塞机制的OpenGateway,性能据说彪悍的一笔,推荐大家试试看,在本系列中,我们两个Gateway都将带大家一起尝试下。
Edge Server,其实按照我个人的项目实践,我更多的是把它用作:
- 服务路由。
- 服务限流。
- 比较土的灰度的支持(灰度支持用这种方法其实不太建议的哈)。+ 还有很重要的一环,就是鉴权认证中的认证,说白了,就是看你请求的资源是否受保护,如果受保护的话,你的账户是否已登录,如果没登录就直接401.
- 其它的无须累述的用途。
API层
API层,其实说白了,就是把后端的服务依据前端不同的消费需求给封装管理。
- API层,理论上来说并不进行太多的业务处理,基本就是透传。
- 如果单个业务请求需要多个组合层的服务来支撑的话,也可以对多个组合层服务进行汇聚(一般情况下很少会出现)。
- 通常也会在这一层需要加上鉴权,也就是说,所有的鉴权在这一层做,检验你的请求是否有权利访问所需的资源。
Composite组合层
组合层,一般情况下是非必须的。
我们在设计微服务的时候,有一个很重要的原则,一般情况下Core的服务是不允许互相调用形成依赖的,最大的原因在于,随着业务的增多,服务的增多,最后依赖会形成蜘蛛网,可维护性会大大降低。
那Core层不允许互相访问,只是单个业务请求有时候需要多个服务协作完成,这种情况下,组合层就应运而生。
- 在单个业务请求,需要多个Core服务来协作融合支撑的时候,我们就需要组合层服务。
- 组合层还有一个比较大的作用就是在分布式事务处理上,如果没有采用分布式事务处理框架,而是自己来实现补偿式事务,则组合层可充当裁判性协调者的作用(具体后续章节会有描述)。
- 另外需要额外多说一下,牵涉到资金流转的服务,一般需要全程鉴权。说白了,就是钱的处理还慎重。
Core层
Core层是我们前面章节所讲述的核心独立域的服务实现。说白了,就是一个小的完整的独立域,就会映射为单个的Core服务。该服务提供该小域之内的服务能力。
Core层的服务,可以直接透过API层对外直接提供服务,亦可以根据业务需求和其它的Core层服务汇聚成组合层服务,然后对外提供服务的能力。
Common公共组件层
公共组件层,顾名思义主要用来存放公共的一些工具和实体类。
- Common Utils。主要用来存放一些工具类,比如:类反射工具,文本处理工具,Bean处理工具,二维码生成工具,图片处理工具等等。
- Common Data。主要用来存放一些公共的Bean。其中主要有:结果集定义Bean,全局常量,全局结果码,以及每个Core服务对外开放服务所用到的Bean(有的同学可能会对此有所顾虑,其实一样的,如果不想放在Common里面,也可以为每个服务,类似于Dubbo一样,定义一个Facade包,专门存放该项目的Bean,个人认为,意义不大)。
- Common Security。主要用来存放系统的一些安全处理相关的包,可以是自定的AuthClient注解,亦可以是Feign的一些Token传递拦截控制工具等。
BasePlatform基础平台层
该层主要用来存放Spring Cloud自身的一些组件,如:
- Gateway。可以是Zuul,也可以是OpenGateway。
- Discovery。可以是Eureka,也可以是Consul的Server,也可以是Zookeeper(Consul和Zookeeper的话需要独立部署,无须再构建项目)。
- ConfigServer。也就是配置中心,可以是Config Server,也可以使阿里NacOS,也可以是携程的Apollo等(如果是NacOS或者Apollo需要独立部署,无须再构建项目)。
- oAuth Server。也就是鉴权认证中心,可以是SpringCloud的AuthServer(基于oAuth2),也可以自己用Shiro构建。
综合上述,可以得出Spring Cloud为基础的体系结构的POM树,参考如下:
image.png
讲到这里,我们后面章节所要搭建的项目结构树基本给大家阐述了一下,总体的思想是,参考已成熟的实践,但无须生搬硬套,记住一句话,适合自己的才是最好的。
后面的章节,我们还要对每个工程包进行阐述,然后就开始我们正式的Spring Cloud之旅,期待。
网友评论