TNG/ArchUnit项目Lang API深度解析:架构规则的优雅表达
引言
在现代软件开发中,架构规则验证是确保代码质量的重要手段。TNG/ArchUnit项目提供了一套强大的API,其中Lang API作为其高级抽象层,让开发者能够用接近自然语言的语法来表达复杂的架构约束。本文将深入解析Lang API的核心概念和使用方法。
基础规则构建
从原始代码到声明式规则
传统方式下,验证架构规则需要编写冗长的过程式代码,例如检查"service包中的类不应访问controller包中的类"这样的规则。这种代码不仅难以编写,更难以阅读和维护。
Lang API通过流畅接口(Fluent Interface)提供了声明式的规则构建方式:
ArchRule rule = ArchRuleDefinition.noClasses()
.that().resideInAPackage("..service..")
.should().accessClassesThat().resideInAPackage("..controller..");
这里的".."是通配符,表示任意层级的子包。这种写法几乎与自然语言描述完全一致,大大提升了代码的可读性。
规则组合
Lang API支持通过逻辑运算符组合多个条件:
noClasses()
.that().resideInAPackage("..service..")
.or().resideInAPackage("..persistence..")
.should().accessClassesThat().resideInAPackage("..controller..")
.orShould().accessClassesThat().resideInAPackage("..ui..");
成员级别规则
除了类级别的规则,Lang API还支持对类成员(方法、字段等)定义规则:
ArchRule rule = ArchRuleDefinition.methods()
.that().arePublic()
.and().areDeclaredInClassesThat().resideInAPackage("..controller..")
.should().beAnnotatedWith(Secured.class);
API提供了多种入口方法:methods()
, fields()
, constructors()
等,以及它们的否定形式。
自定义规则构建
核心概念:谓词与条件
Lang API的核心抽象是DescribedPredicate
(谓词)和ArchCondition
(条件)。大多数架构规则都可以表示为:
classes that ${PREDICATE} should ${CONDITION}
例如,自定义一个检查带有@Payload注解字段的规则:
DescribedPredicate<JavaClass> haveAFieldAnnotatedWithPayload = ...;
ArchCondition<JavaClass> onlyBeAccessedBySecuredMethods = ...;
classes().that(haveAFieldAnnotatedWithPayload).should(onlyBeAccessedBySecuredMethods);
预定义谓词与条件
ArchUnit提供了大量预定义的谓词和条件,通常位于目标类型的Predicates
内部类中。例如:
JavaClass.Predicates.simpleName("Foo")
.and(JavaClass.Predicates.assignableTo(Serializable.class));
条件也可以组合:
ArchCondition<JavaClass> callEqualsOrHashCode =
ArchConditions.callMethod(Object.class, "equals", Object.class)
.or(ArchConditions.callMethod(Object.class, "hashCode"));
高级特性
自定义概念规则
Lang API不仅限于类和成员,可以通过ClassesTransformer
定义任何自定义概念的规则:
ClassesTransformer<BusinessModule> businessModules = ...;
DescribedPredicate<BusinessModule> dealWithOrders = ...;
ArchCondition<BusinessModule> beIndependentOfPayment = ...;
all(businessModules).that(dealWithOrders).should(beIndependentOfPayment);
规则文本控制
可以通过because()
方法添加规则说明,或使用as()
完全自定义规则文本:
classes().that(...).should(...)
.because("这是出于安全考虑的重要约束");
违规忽略
对于遗留系统中的已知问题,可以通过archunit_ignore_patterns.txt
文件忽略特定违规:
# 忽略LegacyService相关的所有违规
.*some\.pkg\.LegacyService.*
最佳实践
- 语义清晰:尽量使规则文本能够准确表达架构意图
- 适度抽象:合理使用预定义谓词和条件,避免过度自定义
- 文档完善:为复杂规则添加充分的说明
- 渐进式验证:对遗留系统使用忽略机制,逐步修复问题
结语
TNG/ArchUnit的Lang API通过高度抽象的DSL,将架构规则从繁琐的实现细节中解放出来,让开发者能够专注于架构意图的表达。掌握这套API不仅能提高开发效率,更能使架构约束成为团队共享的明确规范,而非隐藏在代码中的隐式知识。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考