You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gradle自定义ArchUnit插件无法扫描客户端项目类的问题求助

问题分析与解决方案

核心问题

你的插件当前存在两个关键问题:

  1. 使用Test类型任务完全没必要,反而会混淆类加载环境——doLast块是在插件自身的类加载器中执行的,ArchUnit只能扫描到插件JAR里的类,根本看不到子项目编译后的类文件。
  2. ArchUnit的包扫描逻辑依赖当前类加载器,没有指定从子项目的编译输出目录加载类。

修改后的插件代码

class ArchUnitPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        val runArchUnitTests = project.tasks.register("runArchUnitTests", DefaultTask::class.java) {
            group = "verification"
            description = "Runs ArchUnit tests"

            val sourceSets = project.extensions.getByType<SourceSetContainer>()
            val main = sourceSets.getByName("main")
            
            // 确保先完成源码编译,拿到最新的class文件
            dependsOn(main.compileJavaTaskName)
            
            // 告诉Gradle任务输入是子项目的编译输出目录,支持增量构建
            inputs.dir(main.output.classesDirs)
            outputs.upToDateWhen { true }

            doLast {
                // 把子项目的class目录传递给校验器
                ServiceAnnotationVerifier().verifyServiceAnnotations(main.output.classesDirs.files)
            }
        }
        // 保留依赖test任务的配置(如果需要)
        runArchUnitTests.configure { dependsOn("test") }
    }
}

修改后的规则代码

class ServiceAnnotationVerifier {
    fun verifyServiceAnnotations(classDirs: Collection<File>) {
        // 直接从子项目的编译输出目录导入类文件,而非依赖插件类加载器
        val importedClasses = ClassFileImporter()
            .importLocations(*classDirs.toTypedArray())

        val servicesShouldBeAnnotatedWithService = ArchRuleDefinition.classes()
            .that()
            .resideInAPackage("..service..")
            .and()
            .haveSimpleNameNotEndingWith("Test")
            .should()
            .beAnnotatedWith(Service::class.java)
            .orShould()
            .beAnnotatedWith(Component::class.java)
            .because("Need to ensure that all service classes are annotated with @Service")

        // 可选:如果允许子项目没有service包的情况,取消下面注释
        // servicesShouldBeAnnotatedWithService.allowEmptyShould(true)
        
        servicesShouldBeAnnotatedWithService.check(importedClasses)
    }
}

关键修改说明

  • 切换任务类型:改用DefaultTask替代Test任务,避免Test框架的类路径干扰,简化执行环境。
  • 绑定编译任务:通过dependsOn(main.compileJavaTaskName)确保检查前子项目代码已编译完成。
  • 明确类源路径:直接传递子项目的classesDirs给ArchUnit,让它扫描目标项目的类文件,而非插件自身的类。
  • 支持增量构建:通过inputs.dir标记任务输入,Gradle会自动跳过未修改类的重复检查。

额外注意事项

  • 如果子项目同时用Java和Kotlin编译,main.output.classesDirs会自动包含两种语言的编译输出目录,无需额外处理。
  • 若需要扫描子项目依赖中的类,可以把main.runtimeClasspath也加入importLocations,但通常ArchUnit检查仅关注项目自身代码。
  • 若部分子项目可能没有service包,添加allowEmptyShould(true)到规则中,避免无匹配类时触发报错。

内容的提问来源于stack exchange,提问作者Codex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 04:00:16