☰
Spring Boot项目版本查询全攻略:从pom到运行期定位框架版本
2026/10/22 2:55:25 网站建设 项目流程

1. 查版本前先搞清楚:你要查的是哪个"版本"

接手一个Spring Boot项目,不管是要迭代升级、排查依赖漏洞,还是定位某个诡异报错,第一步往往都是把版本信息摸清楚。很多人在群里问"怎么查看Spring Boot项目的版本",我一般会先反问一句:你想看的是项目自身的版本号,还是Spring Boot框架的版本号?这两者的查找路径完全不同。

项目自身版本号指<groupId>、<artifactId>对应的业务发布版本,在你自己的pom.xml里定义,通常长这样:

<version>2.5.3-RELEASE</version>

而Spring Boot框架版本指的是底层框架的版本,核心体现在spring-boot-starter-parent的<version>字段,或者全局BOM(Bill of Materials,依赖物料清单)中统一管理的版本。

明确这一点很重要。因为Spring Boot的版本管理机制比较特殊——如果你用的是spring-boot-starter-parent作为父工程,那么项目里的spring-boot-starter-web、spring-boot-starter-data-jpa等等组件通常不需要写版本号,它们全部由父工程统一控制。也就是说,改了一个顶层的parent版本号,整棵依赖树的理论版本就跟着变了。

大多数人在开发中被坑到的情况是:项目里既有parent声明,又手工指定了某个依赖的版本,结果与Boost版本控制的预期不一致,导致隐性冲突。所以下文的所有查询方法,我都会顺带提一句"这个结果反映的是哪一个层面的版本",你可以根据自己的需求对号入座。

2. 源码里的版本坐标:pom.xml与build.gradle的读法

2.1 Maven项目:先看parent,再看properties

Maven项目的版本信息首选查看pom.xml。打开项目根目录下的这个文件,从上往下看,第一优先级就是<parent>节点。以最常见的配置为例:

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> <relativePath/> </parent>

这里的2.7.18就是整个项目的Spring Boot框架版本。如果你的项目没有<parent>节点,而是引入了spring-boot-dependencies作为BOM,那就要去<dependencyManagement>里找:

<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.7.18</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

除了parent和BOM,很多项目还会在<properties>节点里定义一组版本属性,例如:

<properties> <java.version>1.8</java.version> <spring-boot.version>2.7.18</spring-boot.version> <mybatis-plus.version>3.5.3</mybatis-plus.version> </properties>

有经验的开发者会养成习惯:拿到一个不熟悉的项目,先搜<properties>里的*version*字段,再对照parent和dependencyManagement里的实际值,基本就能判断出这个项目的版本管理是否规范。

2.2 Gradle项目:plugins块与implementation坐标

如果你拿到的是Gradle构建的Spring Boot项目,核心信息在build.gradle或build.gradle.kts里。以Groovy DSL为例:

plugins { id 'org.springframework.boot' version '2.7.18' id 'io.spring.dependency-management' version '1.0.15.RELEASE' }

这一行的version '2.7.18'就是Spring Boot框架版本。同时,Gradle项目通常还会依赖spring-boot-starter-parent对应的BOM:

dependencyManagement { imports { mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES } }

注意,Gradle插件的版本和依赖BOM的版本应该是同步的。遇到版本不一致的情况,要以dependencyManagement里实际生效的版本为准。

2.3 没有源码只有jar包?先看包里文件名的规律

很多场景下手头只有编译好的jar或war包,没有源码。这时候可以先看文件名,例如order-service-2.5.3.jar这个命名里,order-service是artifactId,2.5.3是项目自身的版本。但仅靠这个文件名判断Spring Boot框架版本不可靠——很多公司自定义了打包命名规范,文件名里的版本号并不一定反映框架版本。

更靠谱的办法是解压jar包,看META-INF/MANIFEST.MF。Spring Boot的可执行jar在构建时会写入一组特定的Manifest属性,其中包含:

Implementation-Title: order-service Implementation-Version: 2.5.3 Spring-Boot-Version: 2.7.18 Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/

Spring-Boot-Version这一项就是框架版本,Implementation-Version是项目自身版本。这一步相当于拿到了最权威的"出厂标识",后续无论是部署排查还是漏洞核对,都以此字段为准。

3. 编译产物的隐形标识:class文件与jar包里的版本密码

除了Manifest文件,编译产物里还有几处可以交叉验证的信息。很多人不知道Spring Boot在构建时会生成一个BuildProperties类的实例,里面记录了一组构建元数据。如果你的项目中引入了spring-boot-starter-actuator,那么这些信息会暴露在运行期接口中。

在编译产物层面,一个更直接的核实方式是查看BOOT-INF/lib/目录下spring-boot-2.7.18.jar这类文件名。由于Spring Boot的依赖仲裁机制,spring-boot核心库的版本号一般与spring-boot-starter-parent一致。因此,找出BOOT-INF/lib/里spring-boot-*.jar的版本,基本就等于拿到了框架版本。

例如在Linux服务器上,未解压直接查看jar包内容:

unzip -p app.jar BOOT-INF/lib/spring-boot-2.7.18.jar > /dev/null && \ unzip -l app.jar | grep -E 'spring-boot-[0-9].*\.jar'

输出结果里会列出所有spring-boot-*.jar的完整文件名,版本号一目了然。我以前在定位一个线上环境问题时,就是从这儿确认了部署包实际用的Spring Boot版本,而项目本身的pom却被某个资源过滤插件悄悄改写了版本号。所以强烈建议:线上排查一切以部署包内实际文件为准,源码里的pom和gradle配置只能作为参考。

3.1 老版本的Spring Boot jar结构差异

这里有一个细节值得展开:Spring Boot的fat jar结构在不同版本之间有过变化。2.x系列的jar目录结构为BOOT-INF/classes和BOOT-INF/lib,外层套着org/springframework/boot/loader的JarLauncher。而Spring Boot1.x时代的结构不一样,它把依赖放在lib/目录下,主类也由org.springframework.boot.loader.JarLauncher加载。所以如果你看到lib/下有一堆jar文件,而没有BOOT-INF目录,大概率用的还是1.x版本。

这个"结构判断法"在拿到一个陌生的老旧部署包时可以很快缩小版本范围,再配合MANIFEST.MF里的Spring-Boot-Version精确确认。新老结构之间还涉及嵌套jar类加载器实现方式的差异,这也是为什么老项目升级Spring Boot版本时,启动类加载偶尔会出现ClassNotFoundException——构建产物里的结构变了,但是某段代码还硬编码着旧的加载路径。

4. 运行期怎么看:Actuator、启动日志与HTTP接口三招并用

有些项目运行在内网服务器上,没法随意翻源码,我通常先通过运行期的方式查版本。成本最低的是启动日志。Spring Boot在启动时会打出一行带有框架版本号的横幅(banner),默认格式如下:

. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.7.18)

日志中的v2.7.18就是框架版本。如果你定制了banner关闭了启动横幅,可以用java -jar app.jar --debug强制开启调试模式,有时会打出更详细的版本信息。

4.1 Actuator的info端点

如果项目引入了spring-boot-starter-actuator,并且management.endpoints.web.exposure.include配置中包含info,那么可以通过HTTP接口读取构建信息。一个典型的请求结果:

GET /actuator/info { "app": { "name": "order-service", "version": "2.5.3", "spring-boot-version": "2.7.18" } }

注意,/actuator/info默认只暴露自定义的info.*配置项,要拿到自动生成的构建信息,需要在application.yml里单独配置:

management: endpoints: web: exposure: include: info,health info: app: name: @project.artifactId@ version: @project.version@ java: version: @java.version@

这里的@project.version@是Maven资源过滤的占位符,构建时会被替换为真实值。如果你想让info端点直接返回Spring Boot的框架版本,可以在配置里显式声明info.spring-boot.version,或者干脆读取build-info.properties中的内容。

4.2 在运行中的应用里用Java代码查

有时候你想在服务运行期间程序化地拿版本号,比如做个健康检查页面展示版本。这时可以通过Spring Boot的SpringApplication相关的元数据来获取:

import org.springframework.boot.SpringBootVersion; import org.springframework.core.SpringVersion; public class VersionUtil { public static String getSpringBootVersion() { return SpringBootVersion.getVersion(); } public static String getFrameworkVersion() { return SpringVersion.getVersion(); } }

如果打出来的Spring Boot版本是null,不要慌,这通常意味着类路径里没有spring-boot的jar包元数据,或者你依赖的是某个封装了Spring Boot的公司内部starter(把元数据重新打包了)。更底层地,可以用Package.getPackage()方式查询:

Package pkg = Package.getPackage("org.springframework.boot"); if (pkg != null) { System.out.println(pkg.getImplementationVersion()); }

这种方式其实也在读取Manifest信息,本质上和看MANIFEST.MF一样。真实项目里,如果版本信息不显示,十有八九是构建插件配置被覆盖,导致jar包的MANIFEST.MF没有生成Implementation-Version。

5. 依赖树里挖真相:Maven与Gradle的版本溯源命令

前面讲的都是"查已知状态"的方法,但真正难的问题是:依赖树里有多个版本的Spring Boot组件,哪个生效?某个传递依赖把Spring Boot版本抬高了,怎么定位根因?这就不得不提Maven和Gradle的依赖分析命令。

5.1 Maven依赖树

mvn dependency:tree -Dverbose

加上-Dverbose参数可以展开所有依赖节点的版本信息,包括那些被依赖仲裁"吞掉"的版本。如果只想看Spring Boot相关的依赖,可以过滤关键包名:

mvn dependency:tree -Dincludes=org.springframework.boot

执行后会输出类似这样的内容:

[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.7.18:compile [INFO] | +- org.springframework.boot:spring-boot-starter:jar:2.7.18:compile [INFO] | | +- org.springframework.boot:spring-boot:jar:2.7.18:compile [INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:2.7.18:compile

所有spring-boot-*组件的版本一致时,说明依赖管理机制运行良好。一旦输出里出现例如spring-boot-starter-web:jar:2.7.18和spring-boot:jar:2.6.15混在一起的情况,就要警惕版本分裂——这在排除依赖冲突的实战中经常遇到。

5.2 Gradle依赖报告

Gradle项目执行:

./gradlew dependencies --configuration runtimeClasspath

输出结果里runtimeClasspath这个配置包含了运行期需要的所有依赖。搜索spring-boot-starter-parent或者spring-boot-dependencies,能看到该BOM引入的版本约束。Gradle的依赖仲裁规则与Maven略有不同,它默认使用最高版本,并且会给出selected与requested两个维度,方便对比。

5.3 依赖版本被锁定的一个经典情况

大多数"查版本"场景都建立在依赖管理正常的前提下。但Spring Boot的dependencyManagement在Maven里属于"全局约束",如果你在业务pom.xml里用<dependency>直接指定了某个Spring Boot组件的版本,那么你的显式指定会覆盖BOM约束。这种问题很难查,因为代码里可能根本没有直接写错版本,而是某个二方starter内部偷偷把版本改掉了。

我遇到过一个实际场景:项目里引入的公司内部common-utilsstarter依赖了spring-boot-starter-log4j2,并且内部锁定了2.6.15,导致项目实际运行在旧版的Spring Boot框架上,但mvn dependency:tree从项目根pom看一切正常。后来是用mvn dependency:tree -Dverbose逐条核对,才发现那个starter里嵌入了版本约束。这个案例提醒我:依赖树永远比pom.xml更真实,因为它展示的是解析后的最终结果。

6. 深度排障:版本号对得上,行为却不对,怎么办

经常有人说"我pom.xml里明明写的是2.7.18,为什么启动日志还是显示2.6.15"。这时候要按顺序排查三类问题。

第一,Maven构建时是否使用了-Dspring-boot.version=xxx之类的参数覆盖。某些CI流水线会在构建命令里追加版本参数,覆盖pom中的属性值,造成"源码版本"和"构建版本"不一致。

第二,本地Maven仓库的.lastUpdated文件缓存了下载失败时的旧版本信息。这种情况下mvn clean不一定有效,可以尝试mvn dependency:purge-local-repository或者手工删除对应目录,再强制重新解析:

mvn clean dependency:resolve -U

第三,父工程(parent)间接引入的spring-boot-dependencies版本与项目显式声明的parent版本不一致。比如你的<parent>指向公司内部的company-parent,它内部又import了一个旧版的spring-boot-dependencies。这种多级parent叠加的场景,只看项目自身pom根本看不出问题,必须用effective-pom一锤定音:

mvn help:effective-pom

输出内容非常长,建议保存成文件后全局搜索spring-boot:

mvn help:effective-pom -Doutput=effective-pom.xml grep -n "spring-boot" effective-pom.xml | head -20

这个命令打印的是Maven最终生效的pom模型,所有继承与覆盖都已经被解析完毕。对比出现在你眼前的"实际版本",再倒推到是哪一层继承引入了旧版本,就能精准定位。

7. 查看版本时的三个常见误判与对应解法

查版本这件事看着简单,实际执行时踩坑率很高。我总结几个高频误判,希望你能绕开。

误判一:把项目版本号当成Spring Boot版本号。有人拿pom.xml里的<version>1.0.0-SNAPSHOT</version>当成Spring Boot版本,然后去搜索漏洞库,结果自然对不上。看准坐标再动手,别混着看。

误判二:用mvn dependency:tree看到多个版本的spring-boot-autoconfigure,没有进一步分析就认为"版本冲突了"。其实Maven依赖仲裁会选最短路径,如果两个路径深度一致,则先声明者优先。判断是否真的生效,要以runtimeClasspath里最终选中的版本为准,不要看到一堆数字就慌。

误判三:从/actuator/info里读到version: null,就断定项目异常。实际上info端点的构建信息依赖build-info.properties文件,如果你的项目没有配置spring-boot-maven-plugin的build-info目标,就不会生成这个文件。解决办法是在插件里显式加入:

<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>build-info</goal> </goals> </execution> </executions> </plugin>

重新构建后,jar包中会出现META-INF/build-info.properties,运行期/actuator/info就能正常返回版本信息了。

8. 我的经验沉淀:查版本信息的最佳组合打法

单独用某一种方法都有盲区,我的建议是把静态与动态手段配合使用:先通过effective-pom确认源码层面的权威版本,再用MANIFEST.MF核对构建产物的真实版本,最后看一次启动日志确认运行期实际加载的版本。三者一致,那这个项目的版本信息就是可信的。

这里给一份我在排查项目时实际使用的核对清单,你可以直接抄作业:

排查层级操作命令/位置关注字段
源码声明pom.xml的parent或BOMspring-boot-starter-parent的version
构建解析mvn help:effective-pom全局搜索spring-boot后的版本值
依赖树mvn dependency:tree -Dverbosespring-boot核心包版本
运行期日志启动banner:: Spring Boot :: (vX.X.X)
部署产物MANIFEST.MFSpring-Boot-Version
程序接口/actuator/info或Java代码spring-boot-version字段

这几项做完,不管你是要升级Boot版本、排查漏洞还是对齐团队规范,手里的信息都足够扎实了。我自己的习惯是每接手一个新项目,先把这份清单走一遍,把版本信息和对应关系写进wiki,后续运维和排障都会省事很多。

最后再说一句实在话:查版本这件事,工具本身没有门槛,难的是建立"版本可信"的意识。只要养成"源码、构建产物、运行期三者相互印证"的习惯,以后碰到任何"版本对不上"的揪心问题,你都能快速锁定真凶,而不是在原地拍脑门。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询