注:开发的编辑器: Intellij Idea,JDK版本是JDK8html
Archunit是什么,官网的英文介绍很好,建议阅读原文,"ArchUnit is a free, simple and extensible library for checking the architecture of your Java code using any plain Java unit test framework. That is, ArchUnit can check dependencies between packages and classes, layers and slices, check for cyclic dependencies and more"。java
简单来讲,它是代码格式、类之间的依赖关系检查工具。git
List-1 最重要的是archunit-junit4依赖github
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>com.tngtech.archunit</groupId> <artifactId>archunit-junit4</artifactId> <version>0.9.1</version> <scope>test</scope> </dependency>
直接上代码了,以下List-2所示,按项目状况,修改本身的"@AnalyzeClasses的packages值"dom
List-2编辑器
import javax.persistence.Entity; import com.tngtech.archunit.junit.AnalyzeClasses; import com.tngtech.archunit.junit.ArchTest; import com.tngtech.archunit.junit.ArchUnitRunner; import com.tngtech.archunit.lang.ArchRule; import org.junit.runner.RunWith; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS; import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS; import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING; /** * @author dmj1161859184@126.com 2018-09-14 23:03 * @version 1.0 * @since 1.0 */ @RunWith(ArchUnitRunner.class) // Remove this line for JUnit 5!! @AnalyzeClasses(packages = "com.mjduan.project") //要扫描的package public class ArchunitTest { /** dao下的类应该以Dao结尾 */ @ArchTest public static final ArchRule DAOs_must_reside_in_a_dao_package = classes() .that() .haveNameMatching(".*Dao") .should() .resideInAPackage("..dao..") .as("DAOs should reside in a package '..dao..'"); /** controller下的类应该以Controller结尾 */ @ArchTest public static final ArchRule CONTROLLERs_must_reside_in_a_dao_package = classes() .that() .haveNameMatching(".*Controller") .should() .resideInAPackage("..controller..") .as("DAOs should reside in a package '..dao..'"); /** util下的类应该以Util结尾 */ @ArchTest public static final ArchRule UTILs_must_reside_in_a_dao_package = classes() .that() .haveNameMatching(".*Util") .should() .resideInAPackage("..util..") .as("DAOs should reside in a package '..dao..'"); /** 有Entity注解的类,应该在domain或者entity包下 */ @ArchTest public static final ArchRule entities_must_reside_in_a_domain_package = classes() .that() .areAnnotatedWith(Entity.class) .should() .resideInAnyPackage("..domain..", "..entity.."); /** 接口类,应该以I开头 */ @ArchTest public static final ArchRule interface_className_must_start_with_I = classes() .that() .areInterfaces() .should() .haveSimpleNameStartingWith("I") .as("Interface should start with I"); /** service下的类,只能被controller下或者时service下的类访问 */ @ArchTest public static final ArchRule services_should_only_be_accessed_by_controllers_or_other_services = classes() .that() .resideInAPackage("..service..") .should() .onlyBeAccessed() .byAnyPackage("..controller..", "..service.."); /** impl下的类,不能是interface */ @ArchTest public static final ArchRule interfaces_must_not_be_placed_in_implementation_packages = noClasses() .that() .resideInAPackage("..impl..") .should() .beInterfaces(); /** 接口类,类名不能以Interface结尾 */ @ArchTest public static final ArchRule interfaces_should_not_have_names_ending_with_the_word_interface = noClasses() .that() .areInterfaces() .should() .haveNameMatching(".*Interface"); /** service下的类,不能调用controller下的类 */ @ArchTest public static final ArchRule services_should_not_access_controllers = noClasses() .that() .resideInAPackage("..service..") .should() .accessClassesThat() .resideInAPackage("..controller.."); /** dao下的类,不能调用controller下的类 */ @ArchTest public static final ArchRule controllers_should_not_access_dao = noClasses() .that() .resideInAPackage("..dao..") .should() .accessClassesThat() .resideInAnyPackage("..controller.."); /** 不该该使用System.* */ @ArchTest private final ArchRule NO_ACCESS_TO_STANDARD_STREAMS = NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS; /** 不该该抛出Exception */ @ArchTest private final ArchRule NO_GENERIC_EXCEPTIONS = NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS; /** 不该该使用java.util.logging来记录日志 */ @ArchTest private final ArchRule NO_JAVA_UTIL_LOGGING = NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING; }
List-2中的代码中已经给出注释,本身能够在项目中运行看下结果。不过发现有个很差的地方是,archunit会扫描test下的类。ide
注:若是要忽略某个规则,那么加上@ArchIgnore就能够了,参考这里。工具
List-3ui
public class ArchitectureTest { // will run @ArchTest public static final ArchRule rule1 = classes().should()... // won't run @ArchIgnore @ArchTest public static final ArchRule rule2 = classes().should()... }
通常出如今遗留系统中。this
图2.1
好比咱们想在Archunit扫描时,忽略DemoInterface和AnnotationDemo,那么在resources下建个"archunit_ignore_patterns.txt"的文件(这个文件名称是固定的,不能修改),在将要忽略的类路径放入其中,注意格式,以下图2.2所示,参考其官网。
图2.2
新建一个interface,名为DemoInterface,以后运行List-2,结果以下图1所示,因为DemoInterface是interface,类名以Interface结尾(List-2中定义不能以Interface结尾),未以I开头(List-2中定义要以I开头):
图3.1 运行List-2后报错信息
能够在Github上看Archunit的例子,Github地址: https://github.com/TNG/ArchUnit-Examples
实际项目中,代码量较多,规范要作好,特别是人员流动是公司中很常见的。