SpringBoot项目:如何构建自动化检查禁止使用System.currentTimeMillis()等方法
几种可行的自动化检查方案
1. 用ArchUnit做架构规则校验(最推荐,简单易集成)
ArchUnit专门用来验证Java项目的架构规则,能直接写代码定义约束,既可以作为单元测试运行,也能无缝集成到CI/CD流水线中。
具体操作:
- 先给Maven添加test范围的依赖:
<dependency> <groupId>com.tngtech.archunit</groupId> <artifactId>archunit-junit5</artifactId> <version>1.2.1</version> <scope>test</scope> </dependency>
- 编写测试类定义规则:
import com.tngtech.archunit.core.domain.JavaClasses; import com.tngtech.archunit.core.importer.ClassFileImporter; import com.tngtech.archunit.lang.ArchRule; import org.junit.jupiter.api.Test; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; public class TimeAccessRulesTest { @Test void noClassExceptSystemInfoServiceShouldCallTimeMethods() { // 替换为你的应用根包路径 JavaClasses allClasses = new ClassFileImporter().importPackages("com.yourcompany.yourapp"); ArchRule timeAccessRule = noClasses() .that().areNotAssignableTo(SystemInfoService.class) .should().callMethodWhere(method -> method.getFullName().equals("java.lang.System.currentTimeMillis()") || method.getFullName().equals("java.util.Date.<init>()") ) .because("只有SystemInfoService允许直接获取系统时间"); timeAccessRule.check(allClasses); } }
- 集成到CI/CD:只要Maven执行
mvn test,这个测试就会自动运行,一旦有其他类调用了禁止的方法,测试直接失败,终止构建流程。
2. 用Checkstyle自定义规则
Checkstyle是常用的静态代码检查工具,可通过自定义规则拦截特定方法调用。
步骤:
- 编写自定义Check类,继承
AbstractCheck,检测方法调用和构造方法调用:
public class ForbiddenTimeAccessCheck extends AbstractCheck { private static final Set<String> FORBIDDEN_CALLS = Set.of( "java.lang.System.currentTimeMillis()", "java.util.Date.<init>()" ); @Override public int[] getDefaultTokens() { return new int[]{TokenTypes.METHOD_CALL, TokenTypes.CTOR_CALL}; } @Override public void visitToken(DetailAST ast) { String targetCall; if (ast.getType() == TokenTypes.METHOD_CALL) { DetailAST dotNode = ast.findFirstToken(TokenTypes.EXPR).findFirstToken(TokenTypes.DOT); String className = dotNode.findFirstToken(TokenTypes.IDENT).getText(); String methodName = ast.findFirstToken(TokenTypes.IDENT).getText(); targetCall = "java.lang." + className + "." + methodName + "()"; } else { String className = ast.findFirstToken(TokenTypes.TYPE).findFirstToken(TokenTypes.IDENT).getText(); targetCall = "java.util." + className + ".()"; } if (FORBIDDEN_CALLS.contains(targetCall)) { String currentClass = getFileContents().getFileName().replace(".java", "").replace('/', '.'); // 替换为你的SystemInfoService全限定类名 if (!currentClass.equals("com.yourcompany.yourapp.service.SystemInfoService")) { log(ast.getLineNo(), "禁止直接调用" + targetCall + ",请使用SystemInfoService"); } } } }
- 将这个类打包成Jar,在Maven的checkstyle插件中引入:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-checkstyle-plugin</artifactId> <version>3.3.0</version> <dependencies> <dependency> <groupId>com.yourcompany.yourapp</groupId> <artifactId>custom-checkstyle-rules</artifactId> <version>1.0.0</version> </dependency> </dependencies> <executions> <execution> <phase>verify</phase> <goals> <goal>check</goal> </goals> </execution> </executions> <configuration> <configLocation>checkstyle.xml</configLocation> </configuration> </plugin>
- 在
checkstyle.xml中配置自定义规则:
<module name="com.yourcompany.yourapp.checkstyle.ForbiddenTimeAccessCheck"/>
- CI执行
mvn verify时,Checkstyle会自动扫描代码,发现违规直接终止构建。
3. SpotBugs自定义检测器(复杂度高,按需选择)
SpotBugs可通过自定义检测器查找代码违规模式,但需要处理字节码层面的分析,实现成本较高,若前两种方案能满足需求,不推荐使用。
4. 单元测试反射扫描(不推荐,局限性大)
可以通过反射扫描所有类的方法,检查是否调用了禁止的方法,但这种方式难以覆盖动态调用场景,实现繁琐且易漏检,仅适合作为补充手段。
内容的提问来源于stack exchange,提问作者e-mre
相关产品推荐
相关产品推荐

