上禮拜才遇到一件怪事:我把 Bug 改完 deploy 上去了,結果同事 build 完跟我說「你根本沒修好」。
後來查了半天搞清楚,他本地快取抓到的是舊的 Snapshot。在 Maven 專案裡,只要沒搞懂 Release 跟 Snapshot 的運作機制,這類怪事就會天天上演。這篇就把兩者的差別和更新邏輯整理一下。
01. Release 跟 Snapshot 差在哪
簡單講:Release 發出去就固定了,Snapshot 隨時會更新。
| 維度 | Release(正式發行版) | Snapshot(快照開發版) |
|---|---|---|
| 版本號格式 | 固定號碼,如 1.0.0、2.1.3 |
結尾加 -SNAPSHOT(必須全部大寫) |
| 核心性質 | 不可變(Immutable):一旦發布嚴禁更動 | 可變(Mutable):內容隨時可能推進與重打 |
| 本地快取機制 | 下載至 ~/.m2/repository 後永遠不再拉取 |
依據更新策略(預設每天)檢查遠端倉庫最新快照 |
| 適用階段 | 正式環境(Production)、對外 API、封測歸檔 | 日常開發、特性分支測試、團隊內部協同 |
在 pom.xml 裡,後綴必須嚴格為大寫的 -SNAPSHOT(例如 1.0.0-SNAPSHOT),前後以連字號
- 隔開。小寫的 -snapshot 會被 Maven 視為一般的純文字 Release 版本號,從而失去快照自動更新的特性!
02. 實戰場景:為什麼開發期需要 Snapshot
為什麼開發期間不能直接用 Release 版號?看一個很常見的微服務依賴情境:
假設有兩個服務:底層提供介面的 order-service,以及依賴它的前端服務
customer-ui。在密集開發階段,order-service 一天可能修修補補發布好幾次:
- 如果都用 Release 版號:每次改一行 code,
order-service就得發一個新版號(1.0.1→
1.0.2)。那customer-ui的開發者就得跟著改pom.xml
裡的版本號,否則本地快取永遠拉不到新程式碼。光改版號和同步通知就煩死了。 - 如果改用 Snapshot 版號:雙方約定好依賴
order-service-1.0.0-SNAPSHOT。雖然檔名看起來都一樣,但發布到遠端
Nexus/Artifactory 時,Maven 底層會自動加上「時間戳記 + 建置序號」(例如1.0.0-20241024.083015-1)。
這樣 customer-ui 在 build 的時候,Maven 會主動去對照遠端的時間戳記;只要遠端有更新的 Snapshot,就會自動抓下來覆蓋本地快取,不用每次改版都手動去改
pom.xml。
03. updatePolicy 更新策略與常見踩坑
「既然 Snapshot 會自動抓最新版,為什麼有時我重新 build 還是沒抓到?」這通常是 <updatePolicy> 設定的問題。
Maven 預設不是每次 build 都會連網檢查的。你可以透過倉庫設定裡的 <updatePolicy> 調整檢查頻率:
pom.xml 或 settings.xml — Snapshot 倉庫更新策略配置
<repositories>
<repository>
<id>internal-nexus</id>
<url>https://nexus.example.com/repository/maven-public/</url>
<snapshots>
<enabled>true</enabled>
<!-- 可選值:always | daily | interval:X | never -->
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
</repositories>
常見的更新策略選項包含:
daily(預設值):每天只連網檢查一次。如果你早上 9 點建置過一次,下午同事推了新快照,本地預設是不會抓取的!除非手動下指令
mvn clean compile -U(-U代表強制檢查更新)。always:每次執行建置命令時,都強制連線遠端倉庫檢查是否有更新版本。interval:X:每隔 X 分鐘檢查一次(例如interval:60)。never:從不主動檢查遠端更新,完全依賴本地既有快取。
很多人為了解決「沒抓到最新 code」的問題,索性在 settings.xml 將所有 Snapshot 都設為
always。結果專案只要依賴模組多一點,每次編譯都要對 Nexus 發幾十次 HTTP 查詢,直接把建置時間拖慢好幾倍。建議維持預設的
daily,有需要時手動加 mvn -U 強制更新就好。
04. 小結
原則其實很單純:
- 開發階段用 Snapshot:自動抓最新程式碼,避免版號無意義一直往上加。
- 準備上線用 Release:確保「今天測過的 jar 包,幾個月後重抓內容依然完全相同」。
把這兩者的邊界劃分清楚,團隊協作時就不會整天為了「誰沒抓到最新依賴」在那邊除錯了。

