SpotBugs 導入指引
導入效應
| 效應 |
說明 |
| 深度靜態分析 |
分析 Bytecode 而非原始碼,能找到更高階的 Bug |
| FindBugs 後繼 |
繼承 FindBugs 的所有規則並持續更新 |
| 數值精度問題 |
偵測 new BigDecimal(0.1) 等浮點數精度問題 |
| 多執行續 Bug |
偵測 Race Condition、Thread Safety 問題 |
| 序列化安全 |
檢查 Serializable 的正確性 |
| 與 ErrorProne 互補 |
ErrorProne 抓編譯期問題,SpotBugs 抓 Bytecode 層級問題 |
1. Maven 導入
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.8.6.6</version>
<configuration>
<effort>Max</effort>
<threshold>Medium</threshold>
<includeFilterFile>spotbugs-exclude.xml</includeFilterFile>
</configuration>
</plugin>
2. Gradle 導入
plugins {
id 'com.github.spotbugs' version '6.1.3'
}
spotbugs {
effort = 'max'
reportLevel = 'medium'
excludeFilter = file('spotbugs-exclude.xml')
}
dependencies {
spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0'
}
3. 執行掃描
# Maven
mvn spotbugs:check # 檢查(CI 用)
mvn spotbugs:gui # GUI 介面查看
mvn spotbugs:spotbugs # 產生 XML 報告
# Gradle
./gradlew spotbugsMain
4. 常見偵測問題
4.1 浮點數精度
// ❌ SpotBugs 警告
BigDecimal price = new BigDecimal(0.1); // NP_NUMBER_TO_STRING_TO BigDecimal constructor
// ✅ 正確寫法
BigDecimal price = new BigDecimal("0.1");
4.2 資源外洩
// ❌ SpotBugs 警告
Connection conn = dataSource.getConnection();
// 忘記 close
// ✅ Try-with-resources
try (Connection conn = dataSource.getConnection()) {
// ...
}
4.3 NullPointer 風險
// ❌ SpotBugs 警告
String value = map.get(key);
value.length(); // 可能 NPE
// ✅ 檢查 null
String value = map.get(key);
if (value != null) {
value.length();
}
4.4 SQL Injection
// ❌ SpotBugs 警告 (FindSecBugs)
String query = "SELECT * FROM users WHERE id = " + userId;
// ✅ 參數化查詢
String query = "SELECT * FROM users WHERE id = ?";
PreparedStatement ps = conn.prepareStatement(query);
ps.setInt(1, userId);
5. SpotBugs 規則分類
| 類別 |
說明 |
| Correctness |
可能是 Bug 的程式碼 |
| Bad Practice |
違反良好實踐 |
| Performance |
效能問題 |
| Security |
安全漏洞 (FindSecBugs) |
| Multithreaded |
多執行續問題 |
| Malicious Code |
惡意程式碼指紋 |
6. 自訂規則
6.1 Exclude 某些檢查
<!-- spotbugs-exclude.xml -->
<FindBugsFilter>
<Match>
<Bug pattern="NP_NULL_ON_SOME_PATH"/>
<Package name="com.example.generated"/>
</Match>
</FindBugsFilter>
6.2 自訂 Detector
public class CustomBugDetector extends OpcodeStackDetector {
@Override
public void sawOpcode(int seen) {
// 自訂偵測邏輯
if (seen == INVOKEVIRTUAL && getNameConstantOperand().equals("exec")) {
reportBadPractice();
}
}
}
7. CI 整合
# azure-pipelines.yml
- stage: StaticAnalysis
jobs:
- job: SpotBugs
steps:
- task: Maven@4
inputs:
goals: 'spotbugs:check'
displayName: 'SpotBugs Analysis'
- task: PublishTestResults@2
condition: failed()
inputs:
testResultsFiles: '**/spotbugsXml.xml'
testResultsFormat: 'JUnit'
8. FindSecBugs(安全插件)
<!-- 安裝 FindSecBugs 插件 -->
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.8.6.6</version>
<configuration>
<pluginList>
<plugin>
<groupId>com.h3xstream.findsecbugs</groupId>
<artifactId>findsecbugs-plugin</artifactId>
<version>1.13.0</version>
</plugin>
</pluginList>
</configuration>
</plugin>
9. 與 ErrorProne 比較
| 特性 |
ErrorProne |
SpotBugs |
| 分析層級 |
編譯期 Source Code |
Bytecode |
| 執行速度 |
快(編譯整合) |
較慢(獨立掃描) |
| 規則類型 |
編譯錯誤/警告 |
深度 Bug 模式 |
| 安全分析 |
基本 |
FindSecBugs 強化 |
| 適用時機 |
開發時 |
CI 階段 |
10. 參考資源