导读:本期聚焦于小伙伴创作的《如何用ArchUnit强制实现仓库层与服务层的单一依赖关系》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何用ArchUnit强制实现仓库层与服务层的单一依赖关系》有用,将其分享出去将是对创作者最好的鼓励。

在分层架构的项目中,仓库层通常作为数据访问的底层模块,服务层负责业务逻辑处理,合理的依赖关系应该是服务层仅依赖对应模块的仓库层,避免出现服务层跨模块依赖仓库、或者仓库层反向依赖服务层的情况。如果依赖关系混乱,会导致模块耦合度升高,后续代码迭代和维护的难度大幅增加。

如何用ArchUnit强制实现仓库层与服务层的单一依赖关系

什么是ArchUnit

ArchUnit是一款基于Java的架构约束测试框架,它可以在单元测试阶段扫描项目的字节码,根据预设的规则校验代码的包结构、类依赖、注解使用等是否符合架构要求,一旦出现违反规则的情况,测试会直接失败并给出明确的错误信息。

分层依赖的常见问题

在没有架构约束的情况下,项目中很容易出现以下不符合预期的依赖情况:

  • 订单服务层的类直接依赖用户仓库层的类,跨模块调用仓库
  • 仓库层的类引入服务层的接口或类,出现反向依赖
  • 服务层同时依赖多个不同模块的仓库,职责边界模糊

用ArchUnit实现单一依赖校验

1. 引入依赖

首先在项目的pom.xml中引入ArchUnit的依赖:

<dependency>
    <groupId>com.tngtech.archunit</groupId>
    <artifactId>archunit-junit5</artifactId>
    <version>1.1.0</version>
    <scope>test</scope>
</dependency>

2. 定义分层规则

假设项目的包结构如下:

  • com.example.service:服务层包,下分order、user等子包
  • com.example.repository:仓库层包,下分order、user等子包

我们需要校验的规则是:服务层的类只能依赖同模块的仓库层类,不能依赖其他模块的仓库,也不能被仓库层依赖

首先定义各个层的标识:

import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.library.Architectures;

// 导入所有项目的类
JavaClasses importedClasses = new ClassFileImporter().importPackages("com.example");

// 定义分层架构
Architectures.LayeredArchitecture layeredArchitecture = Architectures.layeredArchitecture()
    .layer("Service").definedBy("com.example.service..")
    .layer("Repository").definedBy("com.example.repository..");

3. 编写单一依赖规则

接下来添加依赖约束,强制服务层只能访问仓库层,且只能访问同模块的仓库:

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;

// 规则1:服务层只能依赖仓库层,不能依赖其他层
ArchRule serviceOnlyDependRepository = classes()
    .that().resideInAPackage("com.example.service..")
    .should().onlyDependOnClassesThat().resideInAnyPackage(
        "com.example.service..", // 允许依赖同层
        "com.example.repository..", // 允许依赖仓库层
        "java..", // 允许依赖JDK类
        "javax..",
        "org.springframework.." // 允许依赖框架类
    );

// 规则2:仓库层不能依赖服务层,避免反向依赖
ArchRule repositoryNotDependService = classes()
    .that().resideInAPackage("com.example.repository..")
    .should().notDependOnClassesThat().resideInAPackage("com.example.service..");

// 规则3:强制服务层子包只能依赖同子包的仓库层
// 例如com.example.service.order包的类只能依赖com.example.repository.order包的类
ArchRule orderServiceOnlyDependOrderRepo = classes()
    .that().resideInAPackage("com.example.service.order..")
    .should().onlyDependOnClassesThat().resideInAnyPackage(
        "com.example.service.order..",
        "com.example.repository.order..",
        "java..",
        "javax..",
        "org.springframework.."
    );

ArchRule userServiceOnlyDependUserRepo = classes()
    .that().resideInAPackage("com.example.service.user..")
    .should().onlyDependOnClassesThat().resideInAnyPackage(
        "com.example.service.user..",
        "com.example.repository.user..",
        "java..",
        "javax..",
        "org.springframework.."
    );

4. 执行测试

将规则放到JUnit5的测试方法中执行:

import org.junit.jupiter.api.Test;

public class ArchitectureTest {
    @Test
    void testServiceRepositoryDependency() {
        JavaClasses importedClasses = new ClassFileImporter().importPackages("com.example");
        
        // 执行所有规则
        serviceOnlyDependRepository.check(importedClasses);
        repositoryNotDependService.check(importedClasses);
        orderServiceOnlyDependOrderRepo.check(importedClasses);
        userServiceOnlyDependUserRepo.check(importedClasses);
    }
}

规则校验效果

如果代码中出现了违反规则的情况,比如订单服务类依赖了用户仓库:

package com.example.service.order;

import com.example.repository.user.UserRepository; // 跨模块依赖,违反规则

public class OrderService {
    private UserRepository userRepository; // 非法依赖
}

执行测试时会直接失败,错误信息会明确指出哪个类违反了哪条规则,方便开发人员快速定位问题:

ArchUnit error: Rule 'classes that reside in a package com.example.service.order.. should only depend on classes that reside in any package [com.example.service.order.., com.example.repository.order.., java.., javax.., org.springframework..]' was violated (1 times): Class <com.example.service.order.OrderService> depends on <com.example.repository.user.UserRepository> in a field of type <com.example.repository.user.UserRepository>

总结

通过ArchUnit编写架构约束测试,可以在开发阶段就拦截不符合分层依赖规则的代码,强制仓库层和服务层保持单一依赖关系,避免架构随着项目迭代逐渐腐化。这种测试可以集成到CI流程中,每次提交代码都自动执行校验,保证整个团队的代码架构始终符合预期。

ArchUnit仓库层服务层单一依赖关系单元测试修改时间:2026-07-24 03:18:29

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。