ArchUnit在代码检测方面的应用

本文介绍了为何需要进行代码检测,特别是在编程中避免常见错误的重要性。ArchUnit是一个用于检查Java代码架构的库,它允许用户自定义规则进行包、类和层之间的依赖检查。通过示例,展示了如何使用ArchUnit检测第三方工具类的使用以及限制非Controller类使用特定工具类,以防止潜在的问题。此外,还提到了如何将这些检测集成到maven-enforcer-plugin中,并讨论了如何根据项目需求调整检测策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、为什么做代码检测功能

 

        不管使用哪种语言,哪种框架,只要你编程,都会遇到些所谓的“坑”,只能靠代码检测工具自动发现这些问题,因为人脑或者是人并不总是最靠谱的。

也许你已经用了阿里的检查插件P3C,或者SonarQube、JArchitect、checkstyle或者findbugs等等工具来检测来避免,现在介绍一款java的基于字节码的我们可以自定义的,比较通用的检测工具。

 

2、ArchUnit

 

  使用这个工具的目的,其实想利用java反射的方式,基于字节码解析的方式,随心所欲的来检测代码,我们可以随便加规则。

 

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. It does so by analyzing given Java bytecode, importing all classes into a Java code structure. 

 

ArchUnit 在代码风格检测方面做的比较好,比如检测包或类、层之间的依赖是否符合公司的规范。

 

 

3、示例

 

目前项目中的使用:

maven-enforcer-plugin做的代码规范检测,按照官方文档http://maven.apache.org/enforcer/enforcer-api/writing-a-custom-rule.html,自定义规则。

需要引入ArchUnit 自己码方式增加规则,我们得改变maven-enforcer-plugin的执行周期:<phase>process-classes</phase>,不然,还没编译成字节码就执行了,就完全失去了检测机会。

 

1、检测第三方包中的内部工具类不让开发者使用

 

private static final ArchRule NOT_RESIDE_IN_BRAVE_INTERNAL_PACKAGE = ArchRuleDefinition.noClasses().that()
            .resideInAnyPackage("com.xxx..", "com.yyy..")
            .should()
            .accessClassesThat()
            .resideInAnyPackage("brave.internal..", "com.beust.jcommander.internal..")
            .because("第三方jar包的工具类不能使用");

第三方包brave.internal和com.beust.jcommander.internal里的一些工具类,开发经常依赖IDE自动导入,而其实想用的是jdk中的类。

检测结果显示:

Architecture Violation [Priority: MEDIUM] - Rule 'no classes that reside in any package ['com.xxx..', 'com.yyy..'] should access classes that reside in any package ['brave.internal..', 'com.beust.jcommander.internal..'], because 第三方jar包的工具类不能使用' was violated (1 times):
Method <com.xxx.YYYYY.submitScore(java.lang.String, java.lang.Long, int)> calls method <com.beust.jcommander.internal.Sets.newHashSet()> in (YYYYY.java:520)
 

 

2、threadlocal工具类被非controller的业务类大量使用,等改造并行执行业务时,导致一些参数传递失败(其他部门因为这个事情损失了几百万好像是)

 

比如我们的工具类是:ccom.xxx.common.web.util.CommonContextUtil

 

 private static final ArchRule CONTEXT_UTIL_RULE = ArchRuleDefinition.classes().that()
            .areNotAnnotatedWith("org.springframework.web.bind.annotation.RestController")
            .and().areNotAnnotatedWith("org.springframework.stereotype.Controller")
            .should(new ArchCondition<JavaClass>("only be accessed  in controller class") {

                @Override
                public void check(JavaClass item, ConditionEvents events) {
                    Set<String> excludes = SUB_RULE_EXCLUDE.get(RuleTypeEnum.ContextUtilSubRule.name());
                    if (Objects.nonNull(excludes) && !excludes.isEmpty() && excludes.contains(item.getSimpleName())) {
                        return;
                    }

                    java.util.Optional<Dependency> first = item.getDirectDependenciesFromSelf().stream().filter(t -> t.getTargetClass().getName().equals("ccom.xxx.common.web.util.CommonContextUtil")).findFirst();
                    if (first.isPresent()) {
                        String message = String.format(
                                "class  %s 用了ContextUtil类 , %s", item.getFullName(), first.get().getSourceCodeLocation());
                        events.add(SimpleConditionEvent.violated(item, message));
                    }

                }
            }).because("ccom.xxx.common.web.util.CommonContextUtil  多线程切换有隐患, \n 如果想忽略检查,可以配置如下示例 \n" +
                    "<subRuleExclude>\n" +
                    "\t<ContextUtilSubRule>xx.java,yy.java</ContextUtilSubRule>\n" +
                    "</subRuleExclude>");

上面的代码也能写成第一种示例的简化形式。

 

 

简单了写了下,要想使用,可以参考官方文档及demo示例和api。当然这种检测会增加maven编译的时间,我们可以利用git的一些自动触发工具,异步检测,报警到人或群也可以。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dreamer who

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值