拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Maven依赖版本管理利器:versions-maven-plugin实战指南

Maven依赖版本管理利器:versions-maven-plugin实战指南 1. 这个插件到底解决了什么问题做 Java 后端开发的同学尤其是项目里依赖一多、模块一拆肯定都遇到过这种场景一打开 IDE右下角弹出一堆依赖更新的提示但谁也不敢轻易点。升级吧怕 API 变了导致一堆编译错误不升级吧又担心安全问题。然后整个团队决定定期统一升级依赖版本结果打开 pom.xml 一看几十个dependency的版本散落在各个模块里有的继承自父 pom有的直接写在子模块里还有的通过properties管理。手动一个个改那基本等于自找麻烦。我第一次意识到versions-maven-plugin有多好用是在一个 20 多个模块的老项目里做季度依赖升级。当时光梳理哪些依赖能升、哪些不能升就花了两天期间还改错了好几个版本。后来同事告诉我 Maven 官方其实就有一个专门干这事的插件叫versions-maven-plugin它能在命令行里直接列出所有依赖的最新版本、批量修改指定依赖的版本、自动更新插件版本甚至能把版本号统一提取到properties里管理。从那以后我再也没手改过 pom 里的版本号。这篇就来聊聊这个插件的完整用法、我踩过的坑以及怎么把它真正用进日常开发流程。内容是基于我自己的实践总结的适用于 Maven 3.6IDEA 内置的 Maven 也能直接用。核心价值一句话它把“依赖版本管理”从一个纯手动、易出错的工作变成了一个可查询、可批量执行、可回滚的半自动流程。适合所有用 Maven 做依赖管理的 Java 项目尤其适合多模块项目、依赖数量超过 20 个的工程以及需要定期做依赖安全升级的团队。2. 核心目标解析display、update、commit 三大类versions-maven-plugin的所有功能都以 goal目标的形式暴露。它不像有些插件只做一件事它的目标覆盖了整个依赖版本管理的生命周期查看能升什么、决定升什么、执行升级、提交或回滚变更。2.1 三个最常用的查看类命令先记住这几个它们解决的是同一个问题我们当前项目里哪些依赖已经过时了mvn versions:display-dependency-updates列出所有直接依赖的最新可用版本。mvn versions:display-plugin-updates列出所有 Maven 插件的最新可用版本。mvn versions:display-property-updates列出所有由属性管理的版本号的最新值。这三个命令跑起来很像 IDE 里的依赖检查但它们在命令行里输出而且信息更全。它会明确告诉你当前用的版本、最新 release 版本、最新 snapshot 版本以及没有版本更新的依赖。举个例子我在一个 Spring Boot 项目里跑mvn versions:display-dependency-updates输出大概是这样的[INFO] The following dependencies in Dependencies have newer versions: [INFO] com.fasterxml.jackson.core:jackson-databind ............ 2.15.2 - 2.17.0 [INFO] org.apache.commons:commons-lang3 .......................... 3.13.0 - 3.14.0 [INFO] org.springframework.boot:spring-boot-starter-web ........... 3.2.1 - 3.2.5注意这个命令默认会同时检查中央仓库和你在 pom 里配置的镜像仓库。如果你配置了阿里云仓库它走的也是阿里云的元数据。热词里提到的maven配置阿里云仓库在这里就很重要——如果你的仓库网络不通或者镜像没配好这个命令的输出可能会为空不是插件的问题是网络问题。提示第一次运行这个命令会比较慢因为 Maven 需要拉取远程仓库的maven-metadata.xml元数据文件。后面再来就快了本地有缓存。2.2 批量修改命令use-latest-versions 和 use-latest-releases查看类命令只是“望闻问切”真正动手改版本靠的是这两个命令mvn versions:use-latest-versions把当前使用的版本升级到最新版本包括快照版本。mvn versions:use-latest-releases把当前使用的版本升级到最新的 release 正式版。两个命令都会直接修改 pom.xml 文件把依赖的version标签里的内容替换成最新版本号。区别在于use-latest-versions不区分 snapshot 和 release会升级到“最新可用版本”哪怕它是个-SNAPSHOT而use-latest-releases只会升级到最新的正式发行版。实际使用中我强烈建议优先用use-latest-releases。因为生产项目一般不建议直接依赖 SNAPSHOT 版本你永远不知道下一个构建时间点拉到的快照是改了还是没改。还有一个关键参数includes。它可以精确指定要更新的依赖范围而不是全量更新。# 只升级 jackson 相关的依赖 mvn versions:use-latest-releases -Dincludescom.fasterxml.jackson.core:*这个参数遵循 Maven 依赖的 groupId:artifactId 格式支持通配符*。我在做安全漏洞修复时非常依赖这个能力。比如 Spring 爆了一个 CVE你就可以只把 spring 相关的依赖升上去其他一律不动。2.3 提交与回滚commit 和 revert这俩是我觉得这个插件最被低估的功能。很多人在命令后加了-DprocessDependenciestrue之类的参数然后直接跑了跑完才发现 pom 被改得乱七八糟想回去却找不到原始版本。事实上插件自带版本回滚能力。它的机制是这样的执行任何会修改 pom 的 goal 之前插件会在项目目录下生成一个pom.xml.versionsBackup备份文件。之后执行mvn versions:commit会删除备份文件正式确认本次修改。而mvn versions:revert会把修改前的 pom.xml 恢复回来同时检查是否有其他文件被改动并一并回退。所以我的建议流程是先跑 update 类命令 → 检查 git diff → 确认没问题 → 跑 commit。如果用了 IDEA 的版本控制更简单连 commit 都可以不用直接在 git 里看改动不合适就 checkout 回去。但如果你在 CI 脚本或批量处理多个仓库时用命令行操作revert简直是后悔药。2.4 其他值得关注的目标除了上面那些还有几个目标有些场景下非常有用versions:update-properties把所有硬编码在dependency里的版本号提取到properties里统一管理。versions:set手动指定新版本号更新整个项目的版本号常用于发版前的版本切换。versions:set-scm-tag配合 SCM 配置更新打 tag 的信息。versions:lock-snapshots/versions:unlock-snapshots锁定或解锁快照版本号。其中set这个目标值得多说两句。它不只是改父 pom 里的version如果你子模块继承了父模块版本parent标签它会把所有子模块的版本号一并更新。对于用 Maven 管理发布版本号的团队来说一条命令替代了手工改十几个 pom 的操作。3. 实操场景多模块项目的统一版本升级光看目标的列表用处不大真正关键的是怎么组合使用。下面分享三个我实际经历过的典型案例并给出完整操作过程和命令。3.1 场景一20 个模块的父 pom 升级老项目里有一个父 pomparent十几个业务模块通过parent继承它。父 pom 里用properties统一管理一堆第三方依赖的版本号比如properties jackson.version2.15.2/jackson.version guava.version32.1.2-jre/guava.version /properties子模块里引用这些依赖时不写版本号直接用dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId version${jackson.version}/version /dependency这种结构下日常升级其实很简单改父 pom 的属性值即可。但问题在于你不知道哪些属性有新版、哪些没有。我用的是这个命令组合# 第一步查看有哪些属性可以升级 mvn versions:display-property-updates # 第二步直接更新所有属性到最新 release 版 mvn versions:update-properties同样update-properties也支持includes参数。我一般会先跑 display 看看有哪些属性版本落后了然后对重点依赖单独执行mvn versions:update-properties -Dincludescom.fasterxml.jackson.core:*这个场景下最大的坑是update-properties只对properties中定义的依赖版本号生效如果某个依赖的版本是直接硬编码在子模块里的它不会帮你动。所以如果你的项目里有依赖版本号直接写在子模块的dependency里比如dependency groupIdorg.apache.commons/groupId artifactIdcommons-lang3/artifactId version3.13.0/version /dependency你需要的命令是mvn versions:use-latest-releases -Dincludesorg.apache.commons:commons-lang3它会跑到所有子模块里把硬编码的版本号统一替换掉。这也是use-latest-releases的一个隐藏优势它会递归处理所有模块不只是当前 pom。3.2 场景二整仓库依赖批量升级但排除不想动的有一次上级要求整个仓库做一次依赖版本大升级把所有-SNAPSHOT依赖替换成稳定版同时整理版本管理规范。这种大规模变更最怕的就是“它把你不想动的也动了”。我的做法是分两步。第一步先把所有 snapshot 依赖列出来mvn versions:display-dependency-updates -DincludeSnapshotVersionstrue这里有个细节display-dependency-updates默认会显示 SNAPSHOT 版本相对于 RELEASE 版本的情况但要想让 SNAPSHOT 版本的升级也展示出来需要加-DincludeSnapshotVersionstrue。如果不加你可能会漏掉一些处在快照版本但已有新版 release 的依赖。第二步排除掉团队内部稳定不动的模块比如某个内部组件库只更新外部第三方依赖mvn versions:use-latest-releases \ -Dincludescom.fasterxml.jackson.*:*,org.apache.*:*,com.google.*:* \ -Dexcludescom.yourcompany:*:*excludes参数的作用和includes正好相反。它接受同样的格式用于排除你不希望被修改的依赖。这在处理多个内部模块时特别实用——外部依赖可以随便升内部模块版本需要在群里和周知后再升。3.3 场景三IDEA 图形界面也能用但命令行更可靠热词里出现了idea插件开发、vscode插件这类词说明大家在 IDE 里玩插件玩得比较顺手。Maven 的versions-maven-plugin也确实可以直接在 IDEA 的 Maven 工具窗口里双击运行不需要命令行。但我想提个醒IDEA 里直接跑这些 goal输出信息往往不够直观而且不能方便地传参数。比如想加-Dincludescom.fasterxml.jackson.core:*你在 IDEA 的 Maven 面板里操作起来比较麻烦了。我更推荐的组合是命令行跑versions插件的命令然后用 IDEA 的git diff看变更确认没问题后直接在 IDEA 里提交。这样既能享受命令行的控制力又能享受 IDE 的图形化 diff 审查体验。IDEA 里其实有一个隐藏技巧可以在 Maven 面板中点右键某个插件目标选择Run Maven Goal然后手动输入参数。它等价于命令行执行但用的是 IDEA 里配置的 Maven 运行时。如果团队统一使用 IDEA这个方式也算方便。4. 插件配置与常见问题排查实录工具好用归好用但用起来总会碰见各种问题。我把自己在真实项目中遇到的几个典型坑整理成速查表你直接对着查就行。4.1 pom 里怎么配置这个插件versions-maven-plugin不需要强制在 pom 里显式配置才能使用。它作为一个 Maven 官方插件默认会被绑定到默认生命周期里直接命令行敲mvn versions:display-dependency-updates就能运行。但如果需要定制行为比如修改备份文件的后缀、设置忽略某些模块、配置额外的仓库源可以这样build plugins plugin groupIdorg.codehaus.mojo/groupId artifactIdversions-maven-plugin/artifactId version2.16.2/version configuration generateBackupPomstrue/generateBackupPoms excludes excludecom.yourcompany:*/exclude /excludes includes includecom.fasterxml.jackson.*:*/include /includes /configuration /plugin /plugins /build注意这个插件的 groupId 是org.codehaus.mojo不是org.apache.maven.plugins。我第一次用的时候在这里踩了坑一直以为自己写错坐标了。generateBackupPoms参数控制是否生成备份文件。默认是true。如果你在 CI 里运行并且不打算用revert可以设成false避免流水线里产生一堆临时文件。但我个人建议保留备份毕竟后悔药不占多少空间。4.2 常见问题与排查方法问题现象可能原因解决办法运行 display 命令后无任何更新输出镜像仓库配置问题或中央仓库元数据获取失败检查settings.xml里的镜像配置确认能访问远程仓库运行 update-properties 后版本没变依赖版本是硬编码在 dependency 里不是 properties 引用改用 use-latest-releases升级后项目编译报错新版本 API 不兼容先查看 display 命令输出的版本差异或到依赖的仓库确认 release notes改完 pom 想恢复原状但找不到记录没有运行 commit 或 revert备份文件被覆盖查看是否有pom.xml.versionsBackup文件或依赖 git 版本管理使用 use-latest-releases 后 SNAPSHOT 依赖也变了当前依赖本身是 SNAPSHOT并且最新版本是 SNAPSHOT确认依赖的仓库是否配置了 release 和 snapshot 仓库分离idea 里双击插件目标没反应IDEA 的 Maven 面板需要刷新才能识别点击 Maven 面板右上角的刷新按钮重新导入项目多模块项目里只改了部分模块插件默认处理全部模块使用-pl指定模块配合-am同时构建依赖模块4.3 关于仓库配置的关键提醒热词里反复出现maven配置阿里云仓库、maven配置多个镜像仓库这其实和versions插件的使用有强关联。这个插件在判定某个依赖“是否有新版本”时依赖的是远程仓库返回的元数据。如果你配置了多个镜像仓库或者镜像仓库顺序不对结果可能和预期不一致。一个常见的坑是轻量的maven-metadata.xml被缓存到了本地但仓库本身的某个版本被删除或更新了导致缓存数据和真实仓库不一致。遇到这种情况可以强制刷新元数据mvn versions:display-dependency-updates -U-U是 Maven 的强制更新快照参数会强制拉取远程元数据忽略本地缓存。我在排查“明明发新版了但插件查不到”的问题时十次里有八次靠这个解决了。另一个坑是镜像仓库的mirrorOf配置。如果你配了多个镜像比如一个配*一个配central插件在获取元数据时会优先命中匹配的镜像。如果*镜像的网络不稳定也会影响插件的输出结果。建议至少保证central仓库能被稳定访问。4.4 与 IDE 集成时的注意点最后聊聊 IDEA 里使用这个插件的经验。IDEA 的 Maven 面板里Plugins文件夹下能看到versions文件夹展开后就是各个 goal。有些人一开始找不到因为 IDEA 需要先通过刷新按钮同步 pom 变更插件列表才会更新。还有一点IDEA 里执行use-latest-releases这类修改命令后它会自动弹出一个“Maven 项目需要重新导入”的提示。千万要记得点导入否则 IDEA 里旧的项目依赖图还在编译会用错版本。如果你在 IDEA 的 Terminal 里直接敲 Maven 命令用的 Maven 版本和 IDEA 内置的不一定相同。如果团队里有人用 IDEA 内置仓库有人用命令行且本地 Maven 版本差异大可能在versions插件的行为上出现细微差异。遇到这种情况建议在根 pom 的pluginManagement里固定插件版本。5. 进阶技巧把版本更新做成团队规范最后一次带着团队做依赖升级的时候我定了一套流程执行起来特别顺分享给大家作为参考。第一步每周一早上由一个人跑一次mvn versions:display-dependency-updates -U update-report.txt把输出重定向到文件里然后人工扫一眼标出哪些是真正的重大升级Major version、哪些是小升级Minor和补丁Patch。第二步确定升级清单后统一执行mvn versions:use-latest-releases -Dincludes需要升级的依赖列表注意不要一次全量升一次只升一批方便定位问题。我一般按依赖组来分比如这周升jackson下周升spring。第三步升级后立即跑一遍测试mvn clean verify这步是底线。任何依赖升级就算版本号只是从 2.15.2 升到 2.15.3也必须跑完整套测试。因为很多依赖的 patch 版本也可能藏着行为变化。第四步确认没问题后提交提交信息里带上升级的依赖版本列表。如果你的团队用了一些自动生成 changelog 的工具这一步能省很多人力。这个插件还有一个冷门功能它可以与 Maven Enforcer 插件搭配使用规定某些依赖版本不能高于某个值防止“手一抖升到天堂”。在团队协作中加上 Enforcer 规则后即使有人手动改了 pom 里的版本构建时也会被拦下来。6. 最后分享一点我的个人心得用这个插件两年多了最深的体会其实不是“省了多少手动操作”而是它让依赖升级这件事从“看心情”变成“看命令”。每次跑一遍display-dependency-updates我都很清楚这个项目目前有哪些依赖存在版本更新、哪些依赖已经落后太多。对于一个长期维护的 Java 项目这种“透明度”本身就是价值。实际操作中我一直坚持一个习惯任何use-latest-releases或update-properties操作之后第一时间看 git diff。插件只是帮你改了版本号但它不会判断这个升级是否安全。升级到新版后编译是否通过、测试是否全绿这些还是要靠项目自己的质量保障流程来兜底。把插件当成助手而不是决策者它就会成为所有 Java 工程师工具箱里最趁手的那把扳手。
返回列表