在 Spring Boot 项目中,pom.xml 承担了构建描述、依赖声明和插件配置三重职责。它不是简单的依赖列表,而是 Maven 与 Spring Boot 约定优于配置理念的落地载体。理解二者的关系,需要从 Maven 的 POM 模型说起:每个 Maven 项目都通过一个名为 pom.xml 的文件描述自身坐标、依赖、构建方式和插件绑定,而 Spring Boot 在这个模型上叠加了一系列预定义的约定,让开发者不用重复编写繁琐的配置。

pom.xml 在 Spring Boot 项目中的核心角色
一个标准的 Spring Boot 项目 pom.xml 通常包含四大部分:项目坐标、父 POM 继承、依赖声明和构建插件。项目坐标由 groupId、artifactId、version 三个元素确定,它让当前项目在 Maven 仓库中拥有唯一身份。父 POM 继承则是 Spring Boot 最关键的约定入口,通过 parent 元素指定 spring-boot-starter-parent,可以把版本仲裁、编码格式、插件默认配置等一次性带入项目。依赖声明区域使用 dependencies 元素列出需要引入的 starter 或具体库,构建插件区域则通常只放一个 spring-boot-maven-plugin,用于在打包阶段生成可执行 jar。
下面是一个最小化的 Spring Boot Web 项目 pom.xml 示例。注意其中 parent 和 dependencies 的写法,它们直接决定了项目能“少写多少配置”。
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
从这个例子可以看出,pom.xml 把 Spring Boot 项目的依赖和构建信息集中到了一处。Maven 读取这个文件后,会先去解析 parent 继承关系,下载父 POM 及其中的依赖管理配置,再根据 dependencies 列表解析实际要引入的库。整个过程不需要开发者在 Java 代码里做任何额外声明,构建和依赖的边界完全由 pom.xml 划定。
Spring Boot 父 POM 与依赖管理机制
spring-boot-starter-parent 是 Spring Boot 提供的一个特殊父 POM,它本身并不包含任何 Java 代码,而是通过 Maven 的继承机制把大量默认配置传递给子项目。继承之后,开发者可以省略很多插件版本号,比如 maven-compiler-plugin、maven-surefire-plugin 的版本都由父 POM 统一指定。父 POM 还预设了 Java 编译级别、资源过滤规则、测试框架版本等。如果项目不需要自定义这些行为,几乎不用关注底层插件细节。
依赖管理则是父 POM 的另一个重要能力。父 POM 中通过 dependencyManagement 元素锁定了所有 Spring Boot 官方支持的依赖版本,比如 Spring Framework、Jackson、Tomcat、Logback 等。当开发者在 dependencies 中引入 spring-boot-starter-web 时,这个 starter 本身只声明了它需要哪些库,并没有写死版本号,版本由 dependencyManagement 统一提供。这种方式避免了多个 starter 之间出现版本冲突,也保证了不同依赖之间的兼容性。
如果想覆盖某个依赖的版本,只需要在当前项目的 properties 中重新定义对应的版本属性。例如要升级或降级 Spring Framework 的版本,可以这样写:
<properties>
<spring-framework.version>6.1.6</spring-framework.version>
</properties>
这种版本仲裁机制让 pom.xml 在保持简洁的同时又具备灵活性。开发者不需要逐个修改所有依赖的版本号,只需要关注少数关键属性。但要注意,随意覆盖版本可能导致兼容性问题,因为 Spring Boot 官方对版本组合做过大量测试,非官方组合可能出现运行时异常。因此覆盖版本前应当确认目标版本与当前 Spring Boot 版本的兼容情况。
spring-boot-starter 与依赖聚合
starter 是 Spring Boot 对依赖集合的抽象。一个 starter 本身就是一个空的 jar,它只包含 pom.xml 文件,在该文件中通过 dependencies 声明了一组完成特定功能所需的库。比如 spring-boot-starter-web 会引入 spring-web、spring-webmvc、jackson-databind、tomcat-embed-core 等十几个依赖。开发者只需要添加一个 starter,就能获得完整的 Web 开发能力,而不用手动逐个添加底层库。
这种聚合方式改变了传统 Maven 项目的依赖管理习惯。在传统项目中,开发者需要明确知道每个功能对应的具体 artifactId 和版本,稍有不慎就会出现缺包或版本冲突。Spring Boot 通过 starter 把常见场景的依赖组合固化下来,让 pom.xml 的依赖列表大幅缩短。如果需要引入数据访问能力,只需再加一个 spring-boot-starter-data-jpa;需要安全控制就加 spring-boot-starter-security。每个 starter 的内部依赖都由 Spring Boot 团队维护并测试兼容性,这大大降低了集成成本。
当然,starter 也不是万能的。如果项目需要非常精简的依赖集,或者使用了 Spring Boot 未提供的 starter,开发者仍然可以手动声明具体依赖,并自行管理版本。此时可以继续借助 dependencyManagement 的版本锁定能力,只覆盖自己引入的那部分版本,从而保持整体一致性。
Maven 构建生命周期与 Spring Boot 插件
Maven 的构建生命周期由一系列阶段组成,包括 validate、compile、test、package、install 等。Spring Boot 项目默认遵循这些阶段,但在 package 阶段多了一个关键动作:spring-boot-maven-plugin 的 repackage 目标。该目标会把原本由 maven-jar-plugin 生成的普通 jar 改写为可执行 jar,具体做法是将应用代码、依赖 jar 以及一个特殊的引导加载器打包到一起,使得通过 java -jar 命令可以直接启动应用。
如果没有配置 spring-boot-maven-plugin,执行 mvn package 得到的只是一个不包含依赖的普通 jar,运行时必须手动指定 classpath。加上插件后,repackage 目标会在原始 jar 的基础上生成一个后缀为 .jar.original 的备份,并输出可执行 jar。这个可执行 jar 内部使用 Spring Boot 自定义的类加载器来加载嵌套的依赖 jar,从而实现单个文件启动。
以下是一个显式配置启动类的插件示例,适用于主类不在默认包结构下的场景:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.demo.DemoApplication</mainClass>
</configuration>
</plugin>
除了 repackage,spring-boot-maven-plugin 还提供了 run、start、stop 等目标,方便在开发阶段直接运行应用而无需手动打包。例如执行 mvn spring-boot:run 会启动应用并自动监控 classpath 变化,配合 devtools 可以实现热重启。这些目标依赖于 pom.xml 中的配置,因此 pom.xml 不仅影响构建产物,也影响日常开发调试的便利性。
在实际项目中,pom.xml 还常被用来划分多模块结构。父模块的 pom.xml 使用 packaging 为 pom 类型,并声明公共依赖和版本管理;子模块通过 parent 继承父模块,再声明各自独立的依赖。这种结构下,Spring Boot 父 POM 通常放在最顶层,形成一个多层继承链。理解每一层 POM 的职责,有助于在不破坏约定和灵活性的前提下维护复杂的工程。

