如何用ArchUnit实现Repository仅被单个Service使用的架构规则?
实现ArchUnit规则:Repository不可在Service间共享
你需要实现的第二条规则可以通过自定义ArchCondition来检查每个Repository被Service引用的数量,确保每个Repository仅被一个Service使用。以下是完整的实现代码:
import com.tngtech.archunit.core.domain.JavaClass; import com.tngtech.archunit.core.domain.Dependency; import com.tngtech.archunit.lang.ArchCondition; import com.tngtech.archunit.lang.ConditionEvents; import com.tngtech.archunit.lang.SimpleConditionEvent; import com.tngtech.archunit.lang.ArchRule; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; import java.util.Set; import java.util.stream.Collectors; // 假设SUBPACKAGE_NAME_REPOSITORY和SUBPACKAGE_NAME_SERVICE是已定义的常量 @ArchTest static final ArchRule repository_must_only_be_used_by_a_service = classes().that().resideInAnyPackage(SUBPACKAGE_NAME_REPOSITORY).should().onlyHaveDependentClassesThat() .resideInAnyPackage(SUBPACKAGE_NAME_SERVICE); @ArchTest static final ArchRule repository_must_only_be_used_by_one_service = classes().that().resideInAnyPackage(SUBPACKAGE_NAME_REPOSITORY) .should(new ArchCondition<JavaClass>("be used by exactly one Service class") { @Override public void check(JavaClass repository, ConditionEvents events) { // 筛选出直接依赖该Repository的Service类 Set<JavaClass> dependentServices = repository.getDirectDependenciesToSelf() .stream() .map(Dependency::getOriginClass) .filter(service -> service.residesInAnyPackage(SUBPACKAGE_NAME_SERVICE)) .collect(Collectors.toSet()); // 检查Service数量是否为1 if (dependentServices.size() != 1) { String violationMessage = String.format( "Repository %s 被 %d 个Service引用:%s", repository.getSimpleName(), dependentServices.size(), dependentServices.stream().map(JavaClass::getSimpleName).collect(Collectors.joining(", ")) ); events.add(SimpleConditionEvent.violated(repository, violationMessage)); } } });
代码说明
- 自定义ArchCondition:通过
ArchCondition实现自定义检查逻辑,针对每个Repository类执行校验。 - 筛选依赖的Service:使用
getDirectDependenciesToSelf()获取所有直接依赖当前Repository的类,再过滤出属于Service包的类。 - 数量校验:统计符合条件的Service数量,如果不等于1,则生成违规事件,明确提示违规的Repository和对应的Service列表。
注意事项
- 如果需要考虑间接依赖(比如Service通过其他类间接引用Repository),可以将
getDirectDependenciesToSelf()替换为getAllDependenciesToSelf(),但通常业务场景中Service直接注入Repository,直接依赖已经足够。 - 确保
SUBPACKAGE_NAME_REPOSITORY和SUBPACKAGE_NAME_SERVICE的包路径配置正确,比如"..repository.."或具体的包名前缀。
内容的提问来源于stack exchange,提问作者Olli
相关产品推荐
相关产品推荐

