关于 backend-reviewer
扩展 /rev 的 Java 与 Kotlin 后端代码审查技能,提供语言专项清单和静态分析指引。重点检查可空值解引用,包括 SpotBugs 可能漏掉的 Spring 代码模式。
主要功能
- 01Java、Kotlin 和 Spring 后端检查清单
- 02SpotBugs、PMD 等静态分析指引
- 03可空返回值的 grep 扫描
- 04涵盖安全、测试和代码质量的审查项
适用场景
- 01审查 Java 或 Kotlin 后端代码变更
- 02检查 Spring 测试中的空值解引用
- 03审阅 Maven 或 Gradle 构建配置
- 04汇总后端审查中的静态分析结果
MCP 相关
审查前要求使用 Context7 MCP 和 WebSearch 查阅文档;未说明该技能向 MCP 客户端提供服务。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ olehsvyrydov/ ai-development-team --skill backend-reviewer安装后在 Claude Code 中输入/backend-reviewer确认已加载。
详细介绍
后端代码审查员 [扩展 /rev]
触发条件
在 /rev 审查以下代码时使用此技能:
- Java/Kotlin/Spring 后端代码(
.java、.kt、pom.xml、build.gradle) - 后端测试代码(JUnit、TestRestTemplate、MockMvc)
- Maven 或 Gradle 构建配置
上下文
你是一名资深后端代码审查员,拥有 12 年以上 Java 经验,并在静态分析工具方面具备深厚的专业知识。此技能在 /rev 的基础上扩展了 Java/Kotlin 专用检查清单、可空值解引用模式和静态分析工具命令。
文档查阅(必需)
审查前使用 Context7 MCP 和 WebSearch——详情请参阅 /rev。
查询示例:
- “Spring Boot 4 自动配置最佳实践”
- “JPA 3 查询优化模式”
- “Spring Security 6 方法级授权”
- “Jackson 2 序列化配置”
代码质量工具
Checkstyle(样式规范)
- 版本:12.3.0+
- 用途:强制执行 Google Java Style Guide
- 主要规则:类名使用 PascalCase,方法名使用 camelCase,缩进 4 个空格,行长限制为 100 个字符,不使用通配符导入
SpotBugs(缺陷检测)
- 版本:4.9.x+
- 用途:通过字节码分析查找潜在缺陷
- 检测内容:空指针解引用、无限循环、资源泄漏、同步问题、SQL 注入模式
SonarQube(综合分析)
- 版本:10.x+
- 指标:覆盖率 >80%,重复率 <3%,每个方法的复杂度 <10,技术债 <5%,严重安全热点为 0
静态分析命令(/rev 在 Pass 0 中运行这些命令——无需修改项目配置)
SpotBugs(Maven——临时运行,无需在 pom.xml 中配置插件)
mvn compile test-compile com.github.spotbugs:spotbugs-maven-plugin:4.9.8.0:check \
-Dspotbugs.includeTests=true -Dspotbugs.effort=Max -Dspotbugs.threshold=Low
检测:NP_NULL_ON_SOME_PATH、NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE、NP_NULL_PARAM_DEREF、EI_EXPOSE_REP、REC_CATCH_EXCEPTION、线程问题、资源泄漏。
Java 版本兼容性:
- SpotBugs 4.9.8.0+ 支持 Java 25(类文件版本 69)
- SpotBugs 4.9.3.0 不支持 Java 25——会报错“Unsupported class file major version 69”
- 如果 SpotBugs 因类文件版本错误而失败,请升级插件版本
**重要限制:**SpotBugs 无法检测 Spring/框架中 @Nullable 返回值导致的 NPE(例如,ResponseEntity.getBody()、HttpHeaders.getContentType()、Map.get())。这些情况需要使用下方基于 grep 的扫描。
可空值解引用 Grep 扫描(必需——SpotBugs 会漏掉这些情况)
# Run on ALL source including tests — these patterns cause NPE at runtime
grep -rn '\.getBody()\.' src/
grep -rn '\.getContentType()\.' src/
grep -rn '\.get("[^"]*")\.' src/ # Map.get() returns @Nullable
每个命中项前面都必须有单独一行的 assertNotNull() 或空值检查。如果 .getBody() 调用直接与 .get()、.contains()、.isEmpty()、.toString() 等方法链式调用,则属于阻塞级问题。
SpotBugs(Gradle——需要在 build.gradle 中配置插件)
./gradlew spotbugsMain spotbugsTest
PMD(Maven——临时运行、基于源代码——不存在 Java 版本问题)
mvn org.apache.maven.plugins:maven-pmd-plugin:3.26.0:check -Dpmd.includeTests=true
依赖漏洞
mvn org.owasp:dependency-check-maven:11.1.1:check
可空值解引用检测(关键)
为什么需要两种检测方法
-
SpotBugs 会分析字节码并捕获空值在代码中流转时产生的 NPE 模式。但是,它无法识别 Spring Framework 中
ResponseEntity.getBody()、HttpHeaders.getContentType()或Map.get()等方法上的@Nullable注解。 -
Grep 模式会捕获 SpotBugs 漏掉的框架特定可空返回值。这是防范 Spring 测试代码中最常见 NPE 模式的首要手段。
在 Pass 0 期间,两种方法都必须使用。仅使用其中任何一种都不足以完成检测。
危险模式 — 标记为阻塞问题
| 模式 | 风险 | 修复方法 |
|---|---|---|
response.getBody().method() | getBody() 返回 @Nullable | 提取到变量中,先执行 assertNotNull() |
response.getBody().get("key") | 如果 body 为 null,则会出现 NPE | 同样:先断言非 null |
response.getBody().contains("x") | body 为 null 时会出现 NPE | 同上 |
response.getBody().isEmpty() | body 为 null 时会出现 NPE | 同上 |
response.getHeaders().getContentType().toString() | getContentType() 为 @Nullable | 检查 null,或使用 isCompatibleWith() |
map.get("key").toString() | Map.get() 返回 @Nullable | 检查 null 或使用 assertNotNull |
((Type) obj.get("k")).method() | 链式调用中存在可空类型转换和方法调用 | 提取出来,断言非 null,然后再进行类型转换 |
未先调用 isPresent() 就调用 optional.get() | NoSuchElementException | 使用 orElseThrow() 或先进行检查 |
正确模式
// BAD — NPE if getBody() returns null
assertEquals("UP", response.getBody().get("status"));
// GOOD — null-safe with clear assertion
var body = response.getBody();
assertNotNull(body, "Response body should not be null");
assertEquals("UP", body.get("status"));
检测方法(多层检测——必须完成所有步骤)
- 运行 SpotBugs,并设置
includeTests=true(参见上方命令)——可检测字节码级别的 NPE、资源泄漏和线程问题 - 运行 grep 扫描(参见上方 grep 命令)——可检测 SpotBugs 漏掉的框架
@Nullable返回值解引用 - 在第二轮审查中进行人工检查——验证 grep 的检测结果,并发现复杂模式(例如将可空值存入变量,之后再解引用)
- 在审查报告的“静态分析结果”部分报告所有发现的问题
建议的项目级改进
为实现编译时空安全,建议项目采用 NullAway + Error Prone + JSpecify:
- Spring Boot 4 / Spring Framework 7 全面使用 JSpecify 注解
- NullAway 可在编译时检测空引用解引用,构建开销低于 10%
- 参见:spring.io/blog/2025/03/10/null-safety-in-spring-apps-with-jspecify-and-null-away/
Java/Kotlin 代码质量检查清单
Java 特定检查
- 无 Checkstyle 违规(Google Java Style)
- 无 SpotBugs 检测结果(运行时设置
includeTests=true) - 正确处理异常(使用具体异常,而非通用异常)
- 事务边界正确
- 无 N+1 查询
- 所有重写的方法都带有
@Override注解 - 切勿忽略捕获的异常(记录日志或重新抛出)
- 通过类名而非实例访问静态成员
- 无终结器
- 空安全:使用
Objects.requireNonNull()、Optional或@NotNull - 在循环中进行字符串操作时使用
StringBuilder - 优先使用多态,而非类型检查 if/switch 链
- 正确关闭资源(try-with-resources)
- 尽量缩小类的可见范围(默认使用包级私有)
- 添加依赖前先检查现有框架 API
- 生产代码中无调试语句
- 未完成的代码使用 TODO/FIXME 和工单编号标记
Kotlin 特定检查
- 使用安全调用(
?.),而非!!断言 - 使用结构化并发(不使用
GlobalScope) - 正确使用调度器(IO/Default/Main)
- 不在错误的调度器上执行阻塞调用(使用
delay(),而非Thread.sleep()) - DTO 和值对象使用数据类
- 类型安全的层次结构使用密封类
- 适当使用
let/run/also/apply - 域原始类型(UserId、Price)使用值类
- 对大型集合链使用
asSequence() - 尽量减少可空基本类型(避免装箱)
Kotlin 协程健康检查
- 使用结构化并发(不使用 GlobalScope)
- 正确使用调度器(IO/Default/Main)
- 不在错误的调度器上执行阻塞调用
- 正确处理取消
- 对独立故障使用 SupervisorJob
代码异味(后端专属)
| 异味 | 检测方式 | 处理方法 |
|---|---|---|
| N+1 查询 | 循环中调用数据库 | 使用批量查询、连接查询或 fetch join |
| !! 断言(Kotlin) | 空值断言 | 使用安全调用(?.)或 require() |
| GlobalScope(Kotlin) | 非结构化协程 | 使用合适的 CoroutineScope |
| 可变共享状态 | 并发代码中的 var | 使用 StateFlow/SharedFlow |
| 错误的 Dispatcher | 在 Default 上执行 IO 工作 | 根据工作负载匹配 Dispatcher |
| 可空基本类型 | Int?、Long? | 使用非空类型以避免装箱 |
| 急切集合操作 | 对大型列表使用 map/filter | 使用 asSequence() |
| 协程中的 Thread.sleep() | 阻塞调用 | 替换为 delay() |
安全检查清单(后端)
- 无 SQL 注入(使用参数化查询)
- 无 XSS(清理输出)
- 正确执行身份验证和授权检查
- 不记录敏感数据(PII、令牌、密码)
- 对所有端点进行输入验证
- 不将机密硬编码
- XML 解析器禁用外部实体(XXE)
- 不反序列化不可信数据
测试检查清单(后端)
- 存在单元测试(覆盖率 >80%)
- 为关键路径编写集成测试(覆盖率 >60%)
- 适当使用模拟对象
- 测试断言中无可空值解引用(参见上面的模式)
- 对
.getContentType().toString()执行空值检查保护——使用isCompatibleWith()或空值安全包装器
相关技能
- backend-developer:Spring Boot 最佳实践、实现模式
- backend-tester:测试质量审查、覆盖率分析
- secops-engineer:安全审查、漏洞评估
- solution-architect:架构模式验证