项目架构级别规约框架Archunit调研 (3)

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

ArchRule archRule = ArchRuleDefinition.classes() .that().areAssignableTo(EntityManager.class) .should().onlyBeAccessed().byAnyPackage("..persistence.."); 注解检查

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

ArchRule archRule = ArchRuleDefinition.classes() .that().areAssignableTo(EntityManager.class) .should().onlyBeAccessed().byClassesThat().areAnnotatedWith(Transactional.class) 逻辑层调用关系检查

例如项目结构如下:

- com.myapp.controller SomeControllerOne.class SomeControllerTwo.class - com.myapp.service SomeServiceOne.class SomeServiceTwo.class - com.myapp.persistence SomePersistenceManager

例如我们规定:

包路径com.myapp.controller中的类不能被其他层级包引用。

包路径com.myapp.service中的类只能被com.myapp.controller中的类引用。

包路径com.myapp.persistence中的类只能被com.myapp.service中的类引用。

编写规则如下:

layeredArchitecture() .layer("Controller").definedBy("..controller..") .layer("Service").definedBy("..service..") .layer("Persistence").definedBy("..persistence..") .whereLayer("Controller").mayNotBeAccessedByAnyLayer() .whereLayer("Service").mayOnlyBeAccessedByLayers("Controller") .whereLayer("Persistence").mayOnlyBeAccessedByLayers("Service") 循环依赖关系检查

例如项目结构如下:

- com.myapp.moduleone ClassOneInModuleOne.class ClassTwoInModuleOne.class - com.myapp.moduletwo ClassOneInModuleTwo.class ClassTwoInModuleTwo.class - com.myapp.modulethree ClassOneInModuleThree.class ClassTwoInModuleThree.class

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

ClassOneInModuleOne -> ClassOneInModuleTwo -> ClassOneInModuleThree -> ClassOneInModuleOne

编写规则如下:

slices().matching("com.myapp.(*)..").should().beFreeOfCycles() 核心API

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

Core层API

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完成此功能:

JavaClasses classes = new ClassFileImporter().importPackages("com.mycompany.myapp"); Lang层API

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

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

ArchRule rule = classes() // 定义在service包下的所欲类 .that().resideInAPackage("..service..") // 只能被controller包或者service包中的类访问 .should().onlyBeAccessed().byAnyPackage("..controller..", "..service..");

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

JavaClasses classes = new ClassFileImporter().importPackage("com.myapp"); ArchRule rule = // 定义的规则 rule.check(classes); Library层API

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

com.tngtech.archunit.library.Architectures

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

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

代码切片功能,入口是com.tngtech.archunit.library.dependencies.SlicesRuleDefinition。

一般编码规则,入口是com.tngtech.archunit.library.GeneralCodingRules。

PlantUML组件支持,功能位于包路径com.tngtech.archunit.library.plantuml下。

编写复杂的规则

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

定义在controller包下的Controller类的类名称以"Controller"结尾,方法的入参类型命名以"Request"结尾,返回参数命名以"Response"结尾。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppwdp.html