maven中的pom详述

Java教程 2025-10-26

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/javasourceDirectory>
<resources>
    <resource>
        <directory>src/main/resourcesdirectory>
    resource>
resources>

  
<testSourceDirectory>src/test/javatestSourceDirectory>
<testResources>
    <testResource>
        <directory>src/test/resourcesdirectory>
    testResource>
testResources>


<outputDirectory>target/classesoutputDirectory>
<testOutputDirectory>target/test-classestestOutputDirectory>

这就是为什么所有 Maven 项目都长得一样的原因

默认仓库配置

<repositories>
    <repository>
        <id>centralid>
        <name>Central Repositoryname>
        <url>https://repo.maven.apache.org/maven2url>
    repository>
repositories>

所有依赖默认都从 Maven 中央仓库下载。

默认插件配置及默认插件版本管理

构建阶段默认插件作用
compilemaven-compiler-plugin编译源代码
testmaven-surefire-plugin运行单元测试
packagemaven-jar-plugin打包成 JAR 文件
installmaven-install-plugin安装到本地仓库

对不同构建阶段绑定了不同的插件。

默认打包配置


<packaging>jarpackaging>

最小的 POM

POM 用三坐标(groupId、artifactId、version) 的方式唯一标识一个项目。可以理解成项目的身份证。如:

<project> 
  <modelVersion>4.0.0modelVersion> 
  <groupId>com.mycompany.appgroupId> 
  <artifactId>my-appartifactId> 
  <version>1version> 
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>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.13.2version>
        <scope>testscope>
        <optional>falseoptional>
        <exclusions>
            <exclusion>
                <groupId>org.hamcrestgroupId>
                <artifactId>hamcrest-coreartifactId>
            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.examplegroupId>
  <artifactId>project-AartifactId>
  <version>1.0.0version>
  ...
  <dependencies>
    
    <dependency>
      <groupId>mysqlgroupId>
      <artifactId>mysql-connector-javaartifactId>
      <version>8.0.28version>
      <optional>trueoptional>
    dependency>
    
    <dependency>
      <groupId>org.postgresqlgroupId>
      <artifactId>postgresqlartifactId>
      <version>42.3.6version>
      <optional>trueoptional>
    dependency>
  dependencies>
project>

现在,有另一个项目project-B依赖了project-A:

<project>
  <groupId>com.examplegroupId>
  <artifactId>project-BartifactId>
  <version>1.0.0version>
  ...
  <dependencies>
    <dependency>
      <groupId>com.examplegroupId>
      <artifactId>project-AartifactId>
      <version>1.0.0version>
    dependency>
  dependencies>
project>

那么,project-B不会自动传递依赖MySQL和PostgreSQL驱动。如果project-B需要用到MySQL,那么它必须在自己的POM中显式声明MySQL驱动。

  • exclusions: 排除传递性依赖,用于解决依赖冲突。

父 POM 与继承(Parent)

用于从父 POM 继承配置,实现统一管理。类似于JAVA中的继承。

注意点:

  1. 父POM的packaging必须是pom。
  2. 子POM通过元素指定父POM,其中groupId、artifactId、version必须与父POM的坐标一致。
  3. relativePath:指定查找父POM的相对路径。默认值是../pom.xml,即先从本地文件系统查找,如果没找到,再从仓库查找。
  4. 如果设置为空,则表示不从相对路径查找,直接从仓库查找。
  5. 继承的内容:父POM中定义的依赖、插件、属性、依赖管理、插件管理等都可以被继承。

总的来说:

  • 父POM:统一配置、依赖版本、默认设置。
  • 子POM:继承配置、使用依赖、覆盖配置【可以有个性】。

relativePath规则:

设置方式策略适用场景
空标签1. 去本地仓库找 2. 去远程仓库找父POM是知名框架(Spring Boot)
../pom.xml1. 去../pom.xml找 2. 找不到再去仓库父POM在本地项目里

示例1:

子pom文件:

<parent>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-parentartifactId>
    <version>2.7.0version>
    <relativePath/>
parent>

<artifactId>my-appartifactId>

实际生效的配置:


<properties>
    <java.version>11java.version>           
    <maven.compiler.source>11maven.compiler.source>
    <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>


<dependencyManagement>
    
    <spring.version>5.3.20spring.version>
    <jackson.version>2.13.3jackson.version>
    
dependencyManagement>


<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-maven-pluginartifactId>
        plugin>
    plugins>
build>

项目聚合(Modules)

目的: 用于将多个模块/子项目聚合在一起,以便一次性构建整个项目

<project>
  <modelVersion>4.0.0modelVersion>
  <groupId>com.mycompanygroupId>
  <artifactId>my-app-aggregatorartifactId>
  <version>1.0version>
  <packaging>pompackaging>   

  <modules>
    <module>core-modulemodule>   
    <module>service-modulemodule>
    <module>web-modulemodule>
  modules>
project>

这通常用在父 POM(其 packaging 为 pom)中。聚合项目本身可以没有源码,它只是作为一个构建的入口。在聚合项目目录下执行mvn命令,Maven会根据模块间的依赖关系自动确定构建顺序,依次构建每个模块。

聚合和继承经常结合使用:聚合项目同时作为父项目,提供统一的配置管理。这种情况下,聚合项目的pom.xml中既有也有等配置。

示例:

  • 父pom
<project>
    <modelVersion>4.0.0modelVersion>
    
    
    <groupId>com.mycompanygroupId>
    <artifactId>ecommerce-platformartifactId>
    <version>1.0.0version>
    
    
    <packaging>pompackaging>
    
    
    <modules>
        <module>user-servicemodule>      
        <module>product-servicemodule>   
        <module>order-servicemodule>     
        <module>commonmodule>            
    modules>
    
    
    <properties>
        <java.version>11java.version>
        <spring-boot.version>2.7.0spring-boot.version>
    properties>
    
    <dependencyManagement>
        <dependencies>
            
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-dependenciesartifactId>
                <version>${spring-boot.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
        dependencies>
    dependencyManagement>
project>
  • 子模块的配置(以user-service为例)

<project>
    <modelVersion>4.0.0modelVersion>
    
    
    <parent>
        <groupId>com.mycompanygroupId>
        <artifactId>ecommerce-platformartifactId>
        <version>1.0.0version>
        <relativePath>../pom.xmlrelativePath>
    parent>
    
    
    <artifactId>user-serviceartifactId>
    <packaging>jarpackaging>  
    
    <dependencies>
        
        <dependency>
            <groupId>com.mycompanygroupId>
            <artifactId>commonartifactId>
            <version>${project.version}version>
        dependency>
        
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        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>11java.version>
    <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    <maven.compiler.source>${java.version}maven.compiler.source>
    <maven.compiler.target>${java.version}maven.compiler.target>
    <spring.version>5.3.20spring.version>
properties>


<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-contextartifactId>
    <version>${spring.version}version>
dependency>

属性的常见用法:

  • 定义公共属性,如上。
  • 多环境配置【开发、测试、生产环境用不同配置】
<properties>
    
    <env>devenv>
    <server.port>8080server.port>
    <database.url>jdbc:mysql://localhost:3306/devdatabase.url>
properties>

<profiles>
    <profile>
        <id>prodid>
        <properties>
            
            <env>prodenv>
            <server.port>80server.port>
            <database.url>jdbc:mysql://prod-server:3306/proddatabase.url>
        properties>
    profile>
profiles>

构建配置(Build)

用于配置构建过程中的插件和行为。

构建配置可以包含两个主要部分:

  • :用于管理插件的版本和配置,类似于依赖管理,它本身不会实际引入插件,只是提供一种统一管理的方式。子项目可以继承并引用这些插件,而无需指定版本。
  • :实际使用的插件列表,在这里配置的插件会在构建过程中执行。

此外,构建配置还包括:

  • 定义资源文件(非代码文件)如何处理,例如配置文件、图片等。
  • :定义测试资源文件如何处理。
  • 构建输出目录,默认为target。
  • 编译后的class文件输出目录,默认为target/classes。
  • 测试类编译输出目录,默认为target/test-classes。
  • 源代码目录,默认为src/main/java。
  • 测试代码目录,默认为src/test/java。

一般为:

<build>
    
    <sourceDirectory>src/main/javasourceDirectory>
    <testSourceDirectory>src/test/javatestSourceDirectory>
    
    
    <resources>
        <resource>
            <directory>src/main/resourcesdirectory>
            <includes>
                <include>**/*.propertiesinclude>
                <include>**/*.xmlinclude>
            includes>
            <filtering>truefiltering> 
        resource>
    resources>
    
    
    <pluginManagement>
        <plugins>
            
        plugins>
    pluginManagement>
    
    
    <plugins>
        
    plugins>
    
    
    <extensions>
        
    extensions>
build>
  • 示例1
<build>
    <plugins>
        
        <plugin>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-maven-pluginartifactId>
            <version>2.7.0version>
            <configuration>
                <mainClass>com.mycompany.app.ApplicationmainClass>
              
                <excludes>
                    <exclude>
                        <groupId>org.projectlombokgroupId>
                        <artifactId>lombokartifactId>
                    exclude>
                excludes>
            configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>repackagegoal> 
                    goals>
                execution>
            executions>
        plugin>
    plugins>
build>
  • 示例2:

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-compiler-pluginartifactId>
                <version>3.8.1version>
                <configuration>
                    <source>11source>
                    <target>11target>
                configuration>
            plugin>
        plugins>
    pluginManagement>
build>


<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.pluginsgroupId>
            <artifactId>maven-compiler-pluginartifactId>
            
        plugin>
    plugins>
build>
  • 示例3:
<profiles>
    <profile>
        <id>productionid>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.pluginsgroupId>
                    <artifactId>maven-surefire-pluginartifactId>
                    <configuration>
                        <skipTests>trueskipTests> 
                    configuration>
                plugin>
            plugins>
            <resources>
                <resource>
                    <directory>src/main/resources-proddirectory>
                    <filtering>truefiltering>
                resource>
            resources>
        build>
    profile>
profiles>

依赖管理(DependencyManagement)

: 只是一个声明,它并不实际引入依赖。它主要用于统一管理子模块或项目的依赖版本。子模块需要显式声明依赖,但可以省略 version。如:

示例1:

  • 父pom
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.28version>
        dependency>
    dependencies>
dependencyManagement>
  • 子模块 POM:
<dependencies>
    
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
    dependency>
dependencies>

示例2:


<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-dependenciesartifactId>
            <version>2.7.0version>
            <type>pomtype>
            <scope>importscope>  
        dependency>
    dependencies>
dependencyManagement>


<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
        
    dependency>
dependencies>

关键标签:合并另一个POM的依赖管理。类似于继承别人的dependencyManagement一样。

当父POM中配置了,子模块继承的是依赖的管理规则(主要是版本信息),而不是依赖本身。这带来了几个显著优势:

  • 统一版本管理: 所有子模块在引用父POM中声明过的依赖时,只需指定groupId和artifactId,版本号会统一使用父POM中的定义。这能有效避免多模块间的依赖版本冲突。
  • 版本灵活性与覆盖: 如果某个子模块需要特殊版本,它可以在自己的中明确声明版本号,此时子模块的版本号具有优先级,会覆盖父POM中的定义。这为特殊需求的模块提供了灵活性。
  • 按需引入依赖: 子模块只声明自己真正需要的依赖,避免了父POM中所有依赖被自动继承可能导致的冗余和潜在冲突。这让每个模块的依赖更清晰、更精简。

Profile

Profile 允许为不同的环境(如开发、测试、生产)定义不同的配置。它能够覆盖 POM 中的默认配置。

<profiles>
    <profile>
        <id>devid>
        <properties>
            <db.url>jdbc:mysql://localhost:3306/devdb.url>
        properties>
        <activation>
            <activeByDefault>trueactiveByDefault> 
        activation>
    profile>
    <profile>
        <id>prodid>
        <properties>
            <db.url>jdbc:mysql://prod-server:3306/proddb.url>
        properties>
    profile>
profiles>
# 用命令激活
mvn clean install -P prod

一个相对完整的POM

"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.0modelVersion>

    
    <groupId>com.examplegroupId>
    <artifactId>my-webappartifactId>
    <version>1.0.0-SNAPSHOTversion>
    <packaging>warpackaging>

    <name>My Web Applicationname>

    
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.7.0version>
    parent>

    
    <properties>
        <java.version>11java.version>
        <junit.version>5.8.2junit.version>
    properties>

    
    <dependencyManagement>
        <dependencies>
            
        dependencies>
    dependencyManagement>

    
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.junit.jupitergroupId>
            <artifactId>junit-jupiterartifactId>
            <scope>testscope>
        dependency>
    dependencies>

    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>

    
    <profiles>
        <profile>
            <id>devid>
            <properties>
                <activatedProperties>devactivatedProperties>
            properties>
            <activation>
                <activeByDefault>trueactiveByDefault>
            activation>
        profile>
        <profile>
            <id>prodid>
            <properties>
                <activatedProperties>prodactivatedProperties>
            properties>
        profile>
    profiles>
project>

比如:

sip-boot依赖了sip-application

sip-application依赖了sip-orm,sip-sieengine

则sip-boot中会引入sip-orm,sip-sieengine

image.png 0

image.png 0

image.png