maven中的pom详述
什么是pom?
pom(project object model)是maven的基本工作单元。它是一个 xml 文件,其中包含有关项目的信息以及 maven 用于构建项目的配置详细信息。简单来说:pom(pom.xml)就是整个工程的项目规划书,它定义了项目的所有细节:需要什么材料(依赖)、由谁建造(开发者信息)、如何建造(构建配置)、以及项目的版本等。
超级pom
超级 pom 是 maven 的默认 pom。除非显式设置,否则所有 pom 都会扩展超级 pom,这意味着超级 pom 中指定的配置将为项目创建的 pom 继承。超级pom可以理解为maven世界的宪法,所有maven项目都必须遵守。超级pom中定义了一些默认配置,下面列举几个:
默认目录结构
<!-- 源代码目录 -->
<sourcedirectory>src/main/java</sourcedirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<!-- 测试代码目录 -->
<testsourcedirectory>src/test/java</testsourcedirectory>
<testresources>
<testresource>
<directory>src/test/resources</directory>
</testresource>
</testresources>
<!-- 输出目录 -->
<outputdirectory>target/classes</outputdirectory>
<testoutputdirectory>target/test-classes</testoutputdirectory>这就是为什么所有 maven 项目都长得一样的原因。
默认仓库配置
<repositories>
<repository>
<id>central</id>
<name>central repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
</repositories>所有依赖默认都从 maven 中央仓库下载。
默认插件配置及默认插件版本管理
| 构建阶段 | 默认插件 | 作用 |
|---|---|---|
compile | maven-compiler-plugin | 编译源代码 |
test | maven-surefire-plugin | 运行单元测试 |
package | maven-jar-plugin | 打包成 jar 文件 |
install | maven-install-plugin | 安装到本地仓库 |
对不同构建阶段绑定了不同的插件。
默认打包配置
<!-- 默认打包方式就是 jar --> <packaging>jar</packaging>
最小的 pom
pom 用三坐标(groupid、artifactid、version)的方式唯一标识一个项目。可以理解成项目的身份证。如:
<project> <!-- 说:这是个项目 --> <modelversion>4.0.0</modelversion> <!-- 说:用第4版规则 --> <groupid>com.mycompany.app</groupid> <!-- 姓:公司/组织名 --> <artifactid>my-app</artifactid> <!-- 名:项目具体叫啥 --> <version>1</version> <!-- 排行:这是第几个版本 --> </project>
pom核心元素
一个标准的 pom 文件包含以下核心元素:
坐标(coordinates) - 项目的唯一标识
- groupid: 定义项目所属的实际组织或公司,通常使用反向域名。例如:com.google.guava。
- artifactid: 定义实际项目(模块)的名称。例如:guava。
- version: 定义项目的当前版本。例如:31.1-jre。snapshot:表示不稳定、尚在开发中的版本。release:表示稳定的发布版本。
- packaging: 定义项目的打包方式。默认为 jar。其他常见值:war, ear, pom(用于聚合或父pom)。
这三个元素(groupid, artifactid, version)合称为gav,是 maven 世界的唯一身份证。
依赖管理(dependencies)
<dependencies>
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>4.13.2</version>
<scope>test</scope>
<optional>false</optional>
<exclusions>
<exclusion>
<groupid>org.hamcrest</groupid>
<artifactid>hamcrest-core</artifactid>
</exclusion>
</exclusions>
</dependency>
</dependencies>- scope: 依赖范围 : compile: 默认值。对编译、测试、运行都有效。
- provided: 表示 jdk 或容器在运行时已提供(如 servlet-api)。只在编译和测试时使用。
- runtime: 编译时不需要,但测试和运行时需要(如 jdbc 驱动)。
- test: 只在测试时使用(如 junit)。
- system: 与 provided 类似,但必须通过 systempath 显式指定路径(不推荐)。
- import: 仅用于 dependencymanagement 部分,用于从其他 pom 导入依赖管理。
- optional: 标记依赖是否为可选。如果为 true,其他项目依赖本项目时,该依赖不会被传递。【设你开发了一个核心软件,这个软件支持多种数据库(mysql、postgresql等),但是你不希望强制使用你软件的人必须包含所有数据库驱动。你可以把数据库驱动设置为可选。这样,当别人在他的项目中引入你的软件时,他不会自动获得所有这些数据库驱动,他需要明确指定他需要哪个驱动(在自己的pom里面单独引入)】,具体而言:
<project>
<groupid>com.example</groupid>
<artifactid>project-a</artifactid>
<version>1.0.0</version>
...
<dependencies>
<!-- 可选依赖:mysql驱动 -->
<dependency>
<groupid>mysql</groupid>
<artifactid>mysql-connector-java</artifactid>
<version>8.0.28</version>
<optional>true</optional>
</dependency>
<!-- 可选依赖:postgresql驱动 -->
<dependency>
<groupid>org.postgresql</groupid>
<artifactid>postgresql</artifactid>
<version>42.3.6</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>现在,有另一个项目project-b依赖了project-a:
<project>
<groupid>com.example</groupid>
<artifactid>project-b</artifactid>
<version>1.0.0</version>
...
<dependencies>
<dependency>
<groupid>com.example</groupid>
<artifactid>project-a</artifactid>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>那么,project-b不会自动传递依赖mysql和postgresql驱动。如果project-b需要用到mysql,那么它必须在自己的pom中显式声明mysql驱动。
- exclusions: 排除传递性依赖,用于解决依赖冲突。
父 pom 与继承(parent)
用于从父 pom 继承配置,实现统一管理。类似于java中的继承。
注意点:
- 父pom的packaging必须是pom。
- 子pom通过元素指定父pom,其中groupid、artifactid、version必须与父pom的坐标一致。
- relativepath:指定查找父pom的相对路径。默认值是…/pom.xml,即先从本地文件系统查找,如果没找到,再从仓库查找。
- 如果设置为空,则表示不从相对路径查找,直接从仓库查找。
- 继承的内容:父pom中定义的依赖、插件、属性、依赖管理、插件管理等都可以被继承。
总的来说:
- 父pom:统一配置、依赖版本、默认设置。
- 子pom:继承配置、使用依赖、覆盖配置【可以有个性】。
relativepath规则:
| 设置方式 | 策略 | 适用场景 |
|---|---|---|
<relativepath/></font>空标签 | 1. 去本地仓库找 2. 去远程仓库找 | 父pom是知名框架(spring boot) |
<relativepath>../pom.xml</relativepath></font> | 1. 去…/pom.xml找 2. 找不到再去仓库 | 父pom在本地项目里 |
示例1:
子pom文件:
<parent>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-parent</artifactid>
<version>2.7.0</version>
<relativepath/>
</parent>
<artifactid>my-app</artifactid>
<!-- 只写了自己的名字,其他都没写 -->实际生效的配置:
<!-- 自动获得老爸的配置 -->
<properties>
<java.version>11</java.version> <!-- java 11 -->
<maven.compiler.source>11</maven.compiler.source>
<project.build.sourceencoding>utf-8</project.build.sourceencoding>
</properties>
<!-- 自动获得依赖版本管理 -->
<dependencymanagement>
<!-- spring boot 2.7.0 兼容的所有版本 -->
<spring.version>5.3.20</spring.version>
<jackson.version>2.13.3</jackson.version>
<!-- ... -->
</dependencymanagement>
<!-- 自动获得插件配置 -->
<build>
<plugins>
<plugin>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-maven-plugin</artifactid>
</plugin>
</plugins>
</build>项目聚合(modules)
目的:用于将多个模块/子项目聚合在一起,以便一次性构建整个项目。
<project>
<modelversion>4.0.0</modelversion>
<groupid>com.mycompany</groupid>
<artifactid>my-app-aggregator</artifactid>
<version>1.0</version>
<packaging>pom</packaging> <!-- 必须为pom -->
<modules>
<module>core-module</module> <!-- 相对路径,表示聚合项目目录下的core-module目录 -->
<module>service-module</module>
<module>web-module</module>
</modules>
</project>这通常用在父 pom(其 packaging 为 pom)中。聚合项目本身可以没有源码,它只是作为一个构建的入口。在聚合项目目录下执行mvn命令,maven会根据模块间的依赖关系自动确定构建顺序,依次构建每个模块。
聚合和继承经常结合使用:聚合项目同时作为父项目,提供统一的配置管理。这种情况下,聚合项目的pom.xml中既有也有等配置。
示例:
- 父pom
<project>
<modelversion>4.0.0</modelversion>
<!-- 聚合项目的身份证 -->
<groupid>com.mycompany</groupid>
<artifactid>ecommerce-platform</artifactid>
<version>1.0.0</version>
<!-- 关键:打包方式必须是pom -->
<packaging>pom</packaging>
<!-- 聚合的核心:列出所有小弟 -->
<modules>
<module>user-service</module> <!-- 用户服务模块 -->
<module>product-service</module> <!-- 商品服务模块 -->
<module>order-service</module> <!-- 订单服务模块 -->
<module>common</module> <!-- 公共模块 -->
</modules>
<!-- 注意:聚合项目可以同时是父项目 -->
<properties>
<java.version>11</java.version>
<spring-boot.version>2.7.0</spring-boot.version>
</properties>
<dependencymanagement>
<dependencies>
<!-- 统一的依赖版本管理 -->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-dependencies</artifactid>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencymanagement>
</project>- 子模块的配置(以user-service为例)
<!-- user-service/pom.xml -->
<project>
<modelversion>4.0.0</modelversion>
<!-- 既可以认父(继承),又可以被聚合 -->
<parent>
<groupid>com.mycompany</groupid>
<artifactid>ecommerce-platform</artifactid>
<version>1.0.0</version>
<relativepath>../pom.xml</relativepath>
</parent>
<!-- 自己的身份证 -->
<artifactid>user-service</artifactid>
<packaging>jar</packaging> <!-- 子模块通常是jar或war -->
<dependencies>
<!-- 依赖common模块 -->
<dependency>
<groupid>com.mycompany</groupid>
<artifactid>common</artifactid>
<version>${project.version}</version>
</dependency>
<!-- 其他业务依赖 -->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
</dependencies>
</project>- 对比:
不使用聚合:
# 要跑4次命令,还要注意构建顺序! cd common && mvn clean install cd ../user-service && mvn clean install cd ../product-service && mvn clean install cd ../order-service && mvn clean install
使用后:
# 在聚合项目根目录,一次搞定! cd ecommerce-platform mvn clean install # maven自动处理: # 1. 分析模块依赖关系(common → user-service → ...) # 2. 按正确顺序构建 # 3. 一次性输出所有结果
- 一般微服务项目结构示例:
platform/ ├── pom.xml(聚合所有微服务) ├── gateway/(网关服务) ├── user-service/(用户服务) ├── order-service/(订单服务) └── product-service/(商品服务)
属性(properties)
用于定义变量,方便统一管理和复用,常见在父pom中定义公共属性。
<properties>
<java.version>11</java.version>
<project.build.sourceencoding>utf-8</project.build.sourceencoding>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<spring.version>5.3.20</spring.version>
</properties>
<!-- 在依赖中使用属性 -->
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-context</artifactid>
<version>${spring.version}</version>
</dependency>属性的常见用法:
- 定义公共属性,如上。
- 多环境配置【开发、测试、生产环境用不同配置】
<properties>
<!-- 默认开发环境配置 -->
<env>dev</env>
<server.port>8080</server.port>
<database.url>jdbc:mysql://localhost:3306/dev</database.url>
</properties>
<profiles>
<profile>
<id>prod</id>
<properties>
<!-- 生产环境覆盖默认值 -->
<env>prod</env>
<server.port>80</server.port>
<database.url>jdbc:mysql://prod-server:3306/prod</database.url>
</properties>
</profile>
</profiles>构建配置(build)
用于配置构建过程中的插件和行为。
构建配置可以包含两个主要部分:
- :用于管理插件的版本和配置,类似于依赖管理,它本身不会实际引入插件,只是提供一种统一管理的方式。子项目可以继承并引用这些插件,而无需指定版本。
- :实际使用的插件列表,在这里配置的插件会在构建过程中执行。
此外,构建配置还包括:
- resources : 定义资源文件(非代码文件)如何处理,例如配置文件、图片等。
- testresources:定义测试资源文件如何处理。
- directory: 构建输出目录,默认为target。
- outputdirectory: 编译后的class文件输出目录,默认为target/classes。
- testoutputdirectory: 测试类编译输出目录,默认为target/test-classes。
- sourcedirectory: 源代码目录,默认为src/main/java。
- testsourcedirectory: 测试代码目录,默认为src/test/java。
一般为:
<build>
<!-- 1. 源代码目录(可以改默认位置) -->
<sourcedirectory>src/main/java</sourcedirectory>
<testsourcedirectory>src/test/java</testsourcedirectory>
<!-- 2. 资源文件处理 -->
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering> <!-- 是否替换占位符 -->
</resource>
</resources>
<!-- 3. 插件管理(父pom中用) -->
<pluginmanagement>
<plugins>
<!-- 定义插件版本和基础配置 -->
</plugins>
</pluginmanagement>
<!-- 4. 实际使用的插件 -->
<plugins>
<!-- 具体配置每个插件 -->
</plugins>
<!-- 5. 扩展(自定义组件) -->
<extensions>
<!-- 扩展maven核心功能 -->
</extensions>
</build>- 示例1:
<build>
<plugins>
<!-- spring boot打包插件 -->
<plugin>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-maven-plugin</artifactid>
<version>2.7.0</version>
<configuration>
<mainclass>com.mycompany.app.application</mainclass>
<!-- lombok只在编译时起作用,已经变成class了,不需要再打jar包依赖了 -->
<excludes>
<exclude>
<groupid>org.projectlombok</groupid>
<artifactid>lombok</artifactid>
</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal> <!-- 生成可执行jar -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>- 示例2:
<!-- 在父pom中统一管理插件版本 -->
<build>
<pluginmanagement>
<plugins>
<plugin>
<groupid>org.apache.maven.plugins</groupid>
<artifactid>maven-compiler-plugin</artifactid>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</pluginmanagement>
</build>
<!-- 在子pom中引用,不需要写版本 -->
<build>
<plugins>
<plugin>
<groupid>org.apache.maven.plugins</groupid>
<artifactid>maven-compiler-plugin</artifactid>
<!-- 版本从父pom继承 -->
</plugin>
</plugins>
</build>- 示例3:
<profiles>
<profile>
<id>production</id>
<build>
<plugins>
<plugin>
<groupid>org.apache.maven.plugins</groupid>
<artifactid>maven-surefire-plugin</artifactid>
<configuration>
<skiptests>true</skiptests> <!-- 生产环境跳过测试 -->
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources-prod</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</profile>
</profiles>依赖管理(dependencymanagement)
: 只是一个声明,它并不实际引入依赖。它主要用于统一管理子模块或项目的依赖版本。子模块需要显式声明依赖,但可以省略 version。如:
示例1:
- 父pom
<dependencymanagement>
<dependencies>
<dependency>
<groupid>mysql</groupid>
<artifactid>mysql-connector-java</artifactid>
<version>8.0.28</version>
</dependency>
</dependencies>
</dependencymanagement>- 子模块 pom:
<dependencies>
<!-- 不需要写版本,版本由父pom统一管理 -->
<dependency>
<groupid>mysql</groupid>
<artifactid>mysql-connector-java</artifactid>
</dependency>
</dependencies>示例2:
<!-- 直接使用spring boot定义的所有版本 -->
<dependencymanagement>
<dependencies>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-dependencies</artifactid>
<version>2.7.0</version>
<type>pom</type>
<scope>import</scope> <!-- 关键:导入整个版本表 -->
</dependency>
</dependencies>
</dependencymanagement>
<!-- 现在所有spring boot相关的依赖都不用写版本了 -->
<dependencies>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
<!-- 自动使用2.7.0对应的版本 -->
</dependency>
</dependencies>关键标签:合并另一个pom的依赖管理。类似于继承别人的dependencymanagement一样。
当父pom中配置了,子模块继承的是依赖的管理规则(主要是版本信息),而不是依赖本身。这带来了几个显著优势:
- 统一版本管理: 所有子模块在引用父pom中声明过的依赖时,只需指定groupid和artifactid,版本号会统一使用父pom中的定义。这能有效避免多模块间的依赖版本冲突。
- 版本灵活性与覆盖: 如果某个子模块需要特殊版本,它可以在自己的中明确声明版本号,此时子模块的版本号具有优先级,会覆盖父pom中的定义。这为特殊需求的模块提供了灵活性。
- 按需引入依赖: 子模块只声明自己真正需要的依赖,避免了父pom中所有依赖被自动继承可能导致的冗余和潜在冲突。这让每个模块的依赖更清晰、更精简。
profile
profile 允许为不同的环境(如开发、测试、生产)定义不同的配置。它能够覆盖 pom 中的默认配置。
<profiles>
<profile>
<id>dev</id>
<properties>
<db.url>jdbc:mysql://localhost:3306/dev</db.url>
</properties>
<activation>
<activebydefault>true</activebydefault> <!-- 默认激活 -->
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<db.url>jdbc:mysql://prod-server:3306/prod</db.url>
</properties>
</profile>
</profiles># 用命令激活 mvn clean install -p prod
一个相对完整的pom
<?xml version="1.0" encoding="utf-8"?>
<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>
<!-- 坐标 -->
<groupid>com.example</groupid>
<artifactid>my-webapp</artifactid>
<version>1.0.0-snapshot</version>
<packaging>war</packaging>
<name>my web application</name>
<!-- 父pom -->
<parent>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-parent</artifactid>
<version>2.7.0</version>
</parent>
<!-- 属性 -->
<properties>
<java.version>11</java.version>
<junit.version>5.8.2</junit.version>
</properties>
<!-- 依赖管理 -->
<dependencymanagement>
<dependencies>
<!-- 可以在这里管理非spring boot管理的依赖 -->
</dependencies>
</dependencymanagement>
<!-- 依赖 -->
<dependencies>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
<dependency>
<groupid>org.junit.jupiter</groupid>
<artifactid>junit-jupiter</artifactid>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 构建配置 -->
<build>
<plugins>
<plugin>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-maven-plugin</artifactid>
</plugin>
</plugins>
</build>
<!-- 多环境配置 -->
<profiles>
<profile>
<id>dev</id>
<properties>
<activatedproperties>dev</activatedproperties>
</properties>
<activation>
<activebydefault>true</activebydefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<activatedproperties>prod</activatedproperties>
</properties>
</profile>
</profiles>
</project>到此这篇关于史上最全maven中的pom详述的文章就介绍到这了,更多相关maven pom内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论