Skip to content

DDK ArchGuard Starter ​

把分层约束写成可执行的 ArchUnit 规则。写在文档里的分层只是建议,写成测试才是约束——违反即构建失败。

能做什么 ​

规则约束
LAYERED_ARCHITECTURE_RULE四层:..adapter.. / ..ui.. → ..application.. → ..domain..;..infrastructure.. 只为实现领域端口而依赖领域层
THREE_LAYER_ARCHITECTURE_RULE三层:..adapter.. → ..business..;..infrastructure.. 实现业务层接口,不被任何层直接引用
DOMAIN_MUST_NOT_DEPEND_ON_FRAMEWORKS..domain.. 不依赖 Spring、MyBatis(-Plus)、Jackson、JPA
DOMAIN_MUST_NOT_DEPEND_ON_OUTER_LAYERS..domain.. 不依赖应用层、适配层、基础设施层
DDK_INTERNALS_MUST_NOT_BE_USED应用代码不依赖 com.ddk..internal..。这些包是 starter 的实现细节,任何版本都可能变更
MCP_TOOLS_MUST_RESIDE_IN_ADAPTER@McpTool 方法只能声明在 ..adapter..,工具只能经由应用服务访问领域
text
四层                                        三层
  adapter ──► application ──► domain          adapter ──► business
                   │            ▲                            ▲
                   └──► infrastructure                  infrastructure
  • 所有规则在层为空时通过:刚生成的骨架、没有适配层的后台服务,不会因为「某层没有类」而失败。
  • 三层规则不要求业务层框架无关:业务层合并了应用层,应用服务本来就带 @Service、@Transactional,约束的重点是依赖倒置。
  • 两个 archetype 生成的项目都自带使用这些规则的 ArchitectureTest。

引入方式 ​

xml
<dependency>
    <groupId>com.ddk</groupId>
    <artifactId>ddk-archguard-starter</artifactId>
    <version>${ddk.version}</version>
    <scope>test</scope>
</dependency>

必须用 test 作用域:规则常量的类型是 ArchRule,本模块以 compile 作用域依赖 ArchUnit,不加 test 会把 ArchUnit 带进运行期依赖。

java
class ArchitectureTest {

    private final JavaClasses classes = new ClassFileImporter()
            .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_JARS)
            .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
            .importPackages("com.acme.order");

    @Test
    void architectureIsRespected() {
        ArchGuard.check(classes,
                CommonArchRules.LAYERED_ARCHITECTURE_RULE,
                CommonArchRules.DOMAIN_MUST_NOT_DEPEND_ON_FRAMEWORKS,
                CommonArchRules.DDK_INTERNALS_MUST_NOT_BE_USED);
    }
}

单条规则仍然可以用 rule.check(classes) 单独执行。

两个导入选项都不能省:

  • DO_NOT_INCLUDE_JARS:否则 classpath 上包名恰好落进层匹配的库类(DDK 自己的 com.ddk.core.domain 就是)也会被检查;
  • DO_NOT_INCLUDE_TESTS:测试类经常为了构造场景而跨层引用。

违规报告 ​

ArchGuard.check 会执行全部规则,不在第一条失败时中断,然后把结果写到 target/archguard/(可用 -Dddk.archguard.report-dir=... 覆盖):

文件给谁看
violations.md人和 AI 编码代理:按规则分组,每条违规附带具体的修复建议
violations.json解析结果的工具和代理:每条违规包含 rule、class、detail、hint、ruleDescription

断言失败的消息内容与报告一致,只看构建日志也能直接动手修。在生成的四层项目里放一个引用 PO 的领域类,实际输出:

text
Architecture violated: 2 violation(s). Fix the code; do not delete or relax the rules.
Report: target/archguard/violations.md

[LAYERED_ARCHITECTURE_RULE] com.acme.order.domain.model.Order
  Field <com.acme.order.domain.model.Order.state> has type <com.acme.order.infrastructure.orm.po.OrderPO> in (Order.java:0)
  How to fix: 依赖方向应为 adapter → application → domain,infrastructure 只实现 domain.acl 中的接口。……

[DOMAIN_MUST_NOT_DEPEND_ON_OUTER_LAYERS] com.acme.order.domain.model.Order
  Field <com.acme.order.domain.model.Order.state> has type <com.acme.order.infrastructure.orm.po.OrderPO> in (Order.java:0)
  How to fix: 领域层不得引用外层类型:需要的能力在 domain.acl 定义端口并由 infrastructure 实现,需要的数据以参数或值对象传入。
  • 违规所在类从 ArchUnit 描述中的代码单元解析:字段、方法会逐级去掉成员部分,直到命中被导入的类。
  • CommonArchRules 之外的自定义规则标为 CUSTOM,给出通用建议。
  • 检查通过时也会写出空报告,工具可以据此判断结果。

配置项 ​

没有 Spring 配置项。规则是测试期使用的静态常量,本 starter 不包含任何自动配置;唯一的开关是报告目录的系统属性 ddk.archguard.report-dir。

规则是怎么被验证的 ​

每条规则都对着一组测试夹具验证「该过的过、该拦的拦」,而不是只断言常量存在:

text
fixture
├── four/valid        adapter → application → domain ← infrastructure     全部通过
├── four/violation    domain.Order 持有 infrastructure.OrderPO              分层与外层依赖规则拦截
├── four/framework    domain.Order 标注 @Component                          框架无关规则拦截
├── three/valid       adapter → business ← infrastructure                  通过
├── three/violation   business.AccountService 持有 infrastructure.AccountMapper   三层规则拦截
└── empty             没有任何分层包                                        四条规则全部通过

不适用的场景 / 已知问题 ​

  1. 层按包名匹配,包名不可配置。包结构不同的项目需要复制 CommonArchRules 中的规则并修改 definedBy(...)。
  2. consideringAllDependencies() 判定较严:字段类型、方法参数、注解、泛型参数、异常声明都计入依赖,存量项目第一次接入时通常会报出大量违规,需要 ignoreDependency(...) 或分阶段收敛。
  3. 规则仍然偏少:没有包循环依赖检查、命名约定(Repository 接口只在领域层)等规则。

相关阅读 ​

文章以 CC BY-NC-SA 4.0 授权 · 代码片段以 MIT 授权