如何通过外部配置动态传递AnalyzeClasses参数,使用ArchUnit作为适配器执行架构测试
如何让ArchUnit的@AnalyzeClasses动态读取配置文件中的包路径
问题的核心在于,@AnalyzeClasses注解的packages参数要求是编译时常量,所以你直接写${archtest.scan.package}是无法生效的——EL表达式在编译阶段无法被解析成常量值。要实现动态配置包路径的需求,我们需要换一种思路:用编程式的方式替代注解初始化ArchUnit的类扫描。
下面分两种常见场景给出具体实现方案:
场景1:基于Spring Boot的应用
如果你的架构测试是Spring Boot项目的一部分,或者引入该Jar的应用是Spring Boot应用,那么可以借助Spring的@Value注解轻松读取配置:
@SpringBootTest public class ArchitectureTests { // 从application.properties读取配置的扫描包路径 @Value("${archtest.scan.package}") private String scanPackage; @Test void verifyArchitectureRules() { // 手动创建ClassFileImporter,配置导入选项(对应注解里的importOptions) ClassFileImporter importer = new ClassFileImporter() .withImportOption(ImportOption.DoNotIncludeTests.class) .withImportOption(ImportOption.DoNotIncludeJars.class); // 动态扫描指定包下的类 JavaClasses classes = importer.importPackages(scanPackage); // 在这里定义你的架构规则,示例规则:service层只能被controller层访问 ArchRule serviceAccessRule = classes() .that().resideInAPackage("..service..") .should().onlyBeAccessed().byClassesThat().resideInAPackage("..controller.."); // 执行规则检查 serviceAccessRule.check(classes); } }
这种方式下,当其他Spring Boot应用引入你的Jar时,只需要在自己的application.properties中配置archtest.scan.package=com.example.targetpkg,测试就会自动扫描指定的包。
场景2:普通Java应用(非Spring环境)
如果是普通Java项目,可以直接使用Java的Properties类加载配置文件:
import com.tngtech.archunit.core.domain.JavaClasses; import com.tngtech.archunit.core.importer.ClassFileImporter; import com.tngtech.archunit.core.importer.ImportOption; import com.tngtech.archunit.lang.ArchRule; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.InputStream; import java.util.Properties; public class ArchitectureTests { private String scanPackage; @BeforeEach void setUp() throws IOException { // 加载类路径下的application.properties文件 Properties properties = new Properties(); try (InputStream input = getClass().getClassLoader().getResourceAsStream("application.properties")) { properties.load(input); scanPackage = properties.getProperty("archtest.scan.package"); } } @Test void checkArchitectureRules() { ClassFileImporter importer = new ClassFileImporter() .withImportOption(ImportOption.DoNotIncludeTests.class) .withImportOption(ImportOption.DoNotIncludeJars.class); JavaClasses classes = importer.importPackages(scanPackage); // 示例规则:repository层不能依赖controller层 ArchRule dependencyRule = noClasses() .that().resideInAPackage("..repository..") .should().dependOnClassesThat().resideInAPackage("..controller.."); dependencyRule.check(classes); } }
关键注意事项
- 配置文件路径:确保
application.properties放在类路径可访问的位置(比如src/main/resources或src/test/resources),引入该Jar的应用只需在自己的类路径下提供同名配置文件即可覆盖或设置参数。 - 灵活性扩展:编程式的方式不仅支持动态包路径,还可以根据配置动态调整导入选项、规则逻辑,比注解方式更灵活。
- 依赖传递:如果你的Jar是作为测试依赖引入的,要确保引入方的测试类路径能正确加载到配置文件。
内容的提问来源于stack exchange,提问作者Mandar Pandit
相关产品推荐
相关产品推荐

