项‎目架构‎级别规约框架Archunit调‎研

来源:book-london.com   作者:   发表时间:2020-02-12 09:51:02

最近在做一个新项目的时候引入了一个架构方面的需求,就是需要检查项目的编码规范、模块分类规范、类依赖规范等,刚好接触到,正好做个调研。

很多时候,我们会制定项目的规范,例如:

还有很多其他可能需要定制的规范,最终可能会输出一个文档。但是,谁能保证所有参数开发的人员都会按照文档的规范进行开发?为了保证规范的实行,Archunit以单元测试的形式通过扫描类路径(甚至Jar)包下的所有类,通过单元测试的形式对各个规范进行代码编写,如果项目代码中有违背对应的单测规范,那么单元测试将会不通过,这样就可以从CI/CD层面彻底把控项项目架构和编码规范。

一般来说,目前常用的测试框架是Junit4,需要引入Junit4和archunit:

由于-junit4中依赖到slf4j,因此最好在测试依赖中引入一个slf4j的实现,例如logback:

主要从下面的两个方面介绍一下的使用:

需要对代码或者依赖规则进行判断前提是要导入所有需要分析的类,类扫描导入依赖于ClassFileImporter,底层依赖于ASM字节码框架针对类文件的字节码进行解析,性能会比基于反射的类扫描框架高很多。ClassFileImporter的构造可选参数为ImportOption(s),扫描规则可以通过ImportOption接口实现,默认提供可选的规则有:

举个例子,我们实现一个自定义的ImportOption实现,用于指定需要排除扫描的包路径:

ImportOption接口只有一个方法:

其中,Location包含了路径信息、是否Jar文件等判断属性的元数据,方便使用正则表达式或者直接的逻辑判断。

接着我们可以通过上面实现的DontIncludePackagesImportOption去构造ClassFileImporter实例:

得到ClassFileImporter实例后我们可以通过对应的方法导入项目中的类:

导入类的方法提供了多维度的参数,用起来会十分便捷。例如想导入com.sample包下面的所有类,只需要这样:

得到的JavaClasses是JavaClass的集合,可以简单类比为反射中Class的集合,后面使用的代码规则和依赖规则判断都是强依赖于JavaClasses或者JavaClass。

类扫描和类导入完成之后,我们需要定检查规则,然后应用于所有导入的类,这样子就能完成对所有的类进行规则的过滤 - 或者说把规则应用于所有类并且进行断言。

规则定义依赖于ArchRuleDefinition类,创建出来的规则是ArchRule实例,规则实例的创建过程一般使用ArchRuleDefinition类的流式方法,这些流式方法定义上符合人类思考的思维逻辑,上手比较简单,举个例子:

上面展示了自定义新的ArchRule的例子,中已经为我们内置了一些常用的ArchRule实现,它们位于GeneralCodingRules中:

基本使用例子,主要从一些常见的编码规范或者项目规范编写规则对项目所有类进行检查。

例如我们规定:com.myapp.moduleone、com.myapp.moduletwo和com.myapp.modulethree三个包路径中的类不能形成一个循环依赖缓,例如:

把API分为三层,最重要的是"Core"层、"Lang"层和"Library"层。

ArchUnit的Core层API大部分类似于Java原生反射API,例如JavaMethod和JavaField对应于原生反射中的Method和Field,它们提供了诸如getName()、getMethods()、getType()和getParameters()等方法。

此外ArchUnit扩展一些API用于描述依赖代码之间关系,例如JavaMethodCall, JavaConstructorCall或JavaFieldAccess。还提供了例如Java类与其他Java类之间的导入访问关系的API如JavaClass#getAccessesFromSelf()。

而需要导入类路径下或者Jar包中已经编译好的Java类,ArchUnit提供了ClassFileImporter完成此功能:

Core层的API十分强大,提供了需要关于Java程序静态结构的信息,但是直接使用Core层的API对于单元测试会缺乏表现力,特别表现在架构规则方面。

出于这个原因,ArchUnit提供了Lang层的API,它提供了一种强大的语法来以抽象的方式表达规则。Lang层的API大多数是采用流式编程方式定义方法,例如指定包定义和调用关系的规则如下:

编写好规则后就可以基于导入所有编译好的类进行扫描:

Library层API通过静态工厂方法提供了更多复杂而强大的预定义规则,入口类是:

目前,这只能为分层架构提供方便的检查,但将来可能会扩展为六边形架构管道和过滤器,业务逻辑和技术基础架构的分离等样式。

还有其他几个相对强大的功能:

一般来说,内建的规则不一定能够满足一些复杂的规范校验规则,因此需要编写自定义的规则。这里仅仅举一个前文提到的相对复杂的规则:

官方提供的自定义规则的例子如下:

我们只需要模仿它的实现即可,具体如下:

因为导入了所有需要的编译好的类的静态属性,基本上是可以编写所有能够想出来的规约,更多的内容或者实现可以自行摸索。

编辑:

未经授权许可,不得转载或镜像
© Copyright © 1997-2019 by book-london.com all rights reserved