首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >万字长文解析maven

万字长文解析maven

作者头像
Louis XIV
发布2024-12-30 10:04:30
发布2024-12-30 10:04:30
27900
代码可运行
举报
运行总次数:0
代码可运行

这篇文章是5年前写的,从个人博客里又挖出来,多年后再看依然觉得不错,就发出来吧。当时maven的版本是3.5左右,现在已经到3.9了,不过核心机制没什么变化。本文应该能让你了解最核心的maven机制,以及解决常见问题

1 Maven的作用

Java开发绕不开的东西,用过的都清楚,几句话带过:

  1. 自动化构建,管理整个构建周期:清理、编译、测试、生成报告、打包、部署
  2. 依赖管理。
  3. 项目信息管理:项目描述、开发者、版本、许可证等,可以将信息自动生成站点
  4. 仓库管理:提供免费的中央仓库
  5. 敏捷实践:测试驱动开发(TDD)、持续集成等

(不得不说,比go语言强太多,go到现在也没有比较好的依赖管理和构建工具)

2 Maven安装

  1. maven官网(https://maven.apache.org/)载安装包,解压
  2. 配置环境变量 M2_HOME=安装目录,PATH=$M2_HOME/bin
  3. 配置settings.xml
  • 把安装包内的settings.xml复制到$HOME/.m2/settings.xml
  • 个人习惯,先修改两个东西:

现在IntellJ IDEA中已经集成了maven,如果都在IDE中操作,不下载maven也是可以的,但是settings.xml一定要改。

3 构件 Artifact

在项目中每一个pom(Project Object Model) 文件通过package命令打包后都会生成一个构件(artifact 也可翻译为制品),构件的唯一性通过坐标来确定。而构件之间又有依赖关系,在pom文件中通过dependencies来管理依赖,有些人也会不太规范地把构件称为依赖 dependency

有一类比较特殊的构件叫“插件”,在插件章节中说明

3.1 坐标

Maven中通过坐标来标识构件,构成坐标的元素(4+1):groupId,artifactId,version,packaging,classifier。

  • groupId 一般是项目名称
  • artifactId 是项目中的模块名称
  • version 版本,关于快照版本和发布版本见仓库分类
  • packaging 打包方式,可以是jar/war/pom等,默认值是jar
  • classifier 当上述4要素无法唯一确定坐标时就要用到这个字段,可以简单理解为标签或分类,例如可以是:javadoc、sources、jdk7

构件的文件名规则:artifactId-version[-classifier].packaging

在本地仓库目录中,顺着groupId往下找,就能找到对应的构件

4要素通过pom文件直接定义,但classifier不能直接定义,需要通过附加插件生成。例如javadoc插件可以生成javadoc的classifier。

3.2 依赖范围

maven在引入依赖时是需要指定依赖范围的,也可以理解为作用域(scope),依赖只在指定作用域内生效。 依赖范围一共有以下几种:compile,test,provided,runtime,system,import

maven项目过程中有三种classpath:编译期classpath,测试期classpath,运行期classpath

  • compile 默认的依赖范围,在编译、测试、运行阶段都产生作用
  • test 只在测试阶段有用,例如junit,在编译和运行阶段都无法使用
  • provided 只在编译和测试阶段有效,运行时无效(即不参与打包)。例如servlet-api,因运行时容器已提供,所以运行时无需引入
  • runtime 只对测试和运行阶段有效
  • system 与provided相同,不同的是需要用systemPath引入本地jar包,不推荐使用
  • import 只在dependencyManagement结点中使用,用于import另一个pom的dependencyManagement

3.3 依赖传递性

依赖的传递性可以简单理解为:A依赖了B,B依赖C,那么A会自动依赖C

依赖范围会对传递性的影响,如下表, 第一列表示A对B的依赖范围,第一行表示B对C的依赖范围,中间结果表示A对C的依赖范围

"-"表示不会传递依赖

3.4 依赖冲突

有依赖就会产生依赖冲突,例如存在C的两个版本C1和C2,现有以下两个依赖链路:

代码语言:javascript
代码运行次数:0
运行
复制
A -> B -> C1
A -> C2

这时C存在依赖冲突,maven有一个依赖仲裁机制:

  1. 路径最短优先
  2. 路径长度相同时,最先声明优先

上述情况因C2的依赖路径最短,因此C2最终生效。

如果依赖仲裁结果不是预期结果,可以通过调整依赖路径长度,或使用exclusions来排除依赖

3.4 依赖分析插件

当依赖树特别复杂时,需要通过maven的dependency插件来对依赖进行分析,dependency插件是maven默认引入的,可以直接使用。

  • mvn dependency:list [-DoutputFile=dep.txt] 可以用来查看已解析的依赖列表,只输出依赖仲裁结果
  • mvn dependency:tree 输出依赖树
  • mvn dependency:analyze 依赖分析(可以分析出使用但未声明,声明但未使用,未使用的依赖可能可以删除)

dependency:analyze分析出的结果可能并不准确,因为该命令只检索java代码,不能检索到xml文件中引用的类。

4 仓库 Repository

仓库是保存构件的地方。

4.1 仓库分类

按仓库所处位置来分类:

  • 本地仓库 位于本地的仓库,可在settings.xml中配置
  • 中央仓库 maven官方提供的中央仓库central
  • 私服 个人或公司搭建的局域网仓库,可做为中央仓库的缓存
  • 其他公共库 Jboss的仓库、阿里巴巴的仓库等

常用公共库地址:

按类型分:

  • host 宿主仓库,可以上传或部署构件
  • proxy 代理仓库,用于代理其他远程仓库
  • group 仓库组,将多个仓库合并成仓库组
  • virtual 虚拟仓库,只在maven1使用

按存储策略分:

  • release 只存储release构件
  • snapshot 只存储snapshot构件

release和snapshot

构件分为发布版本和快照版本,在version中如果以-SNAPSHOT结尾,则为快照版本,否则是发布版本。发布版本是稳定版,使用mvn deploy部署到远程仓库时会自动部署到release仓库中,并且只能部署一次,再次部署会直接失败。快照版本使用mvn deploy部署到远程仓库时会部署到snapshot仓库中,每次部署都会生成一个带时间戳的快照版本。

4.2 仓库配置

本地仓库地址,由settings.xml中的localRepository属性定义

远程仓库有几种配置方法:

  1. pom文件的repositories节点,例如
代码语言:javascript
代码运行次数:0
运行
复制
<repository>
  <id>releases</id>    <!-- 仓库唯一标识 -->
  <name>Releases</name>  <!-- 仓库名称 -->
  <releases>  <!-- 配置发布版本策略 -->
    <enabled>true</enabled>  <!-- 允许从该仓库下载release的构件 -->
    <updatePolicy>never</updatePolicy>
    <checksumPolicy>warn</checksumPolicy>
  </releases>
  <snapshots>  <!-- 配置快照版本策略 -->
    <enabled>false</enabled>  <!-- 禁止从该仓库下载snapshot的构件 -->
  </snapshots>
  <url>http://repo.yourdomain.com/nexus/content/repositories/releases/</url>
  <layout>default</layout>  <!-- 布局,使用默认 -->
</repository>
  • updatePolicy 更新策略,表示从该仓库检查更新的频率,默认值daily。其他可选值有 daily:每天检查一次 never:从不检查更新 always:每次构建都检查更新 interval:X:每隔X分钟检查一次更新
  • checksumPolicy 校验和检查策略 在下载构件的时候,maven会验证校验和文件,如果验证失败就做相应处理。可选值有 warn:默认值,输出警告信息 fail:直接构建失败 ignore:忽略校验和错误

<强制更新> 有时会遇到jar包更新不到本地的情况,可以在执行maven命令时加上-U参数强制检查更新,如mvn clean package -U <插件仓库> 远程插件仓库配置:与普通仓库相同,只是要配置到pluginRepositories结点下

2. 在settings.xml中配置仓库

POM中配置的仓库只能给当前项目使用,如果要配置全局仓库,可以在settings.xml中配置profilerepositories,配置方式与pom相同

3. 配置仓库镜像

仓库镜像:如果仓库X可以提供仓库Y存储的所有内容,则X是Y的一个镜像。

如果公司有搭建私服,可以在私服上配置代理仓库,另外再配置一个仓库组,这个仓库组就可以作为所有仓库的镜像。本地开发时只需将这一个仓库配置为镜像即可。在settings中配置:

代码语言:javascript
代码运行次数:0
运行
复制
<mirrors>
  <mirror>
    <id>public</id>
    <mirrorOf>*</mirrorOf>
    <name>Public Repositories</name>
    <url>http://repo.yourdomain.com/nexus/content/groups/public/</url>
  </mirror>
</mirrors>

mirrorOf表示镜像的是哪个仓库,多个仓库用逗号隔开,*号表示镜像所有仓库,如上配置以后对所有其他仓库的访问都会转到该仓库上。

镜像仓库与其他仓库的区别

  1. 配置不同,镜像仓库不能配置更新策略
  2. 镜像仓库会完全屏蔽被镜像仓库,例如配置了central镜像,当镜像仓库挂掉后,maven也不会尝试再访问central(被完全屏蔽了)
  3. 仓库检索顺序不同

4.3 仓库的检索顺序

代码语言:javascript
代码运行次数:0
运行
复制
local_repo > settings_profile_repo > pom_profile_repo 
> pom_repositories > settings_mirror > central

4.4 将构件发布到远程仓库

mvn deploy命令将构件发布到远程仓库,在此之前还需要在POM中配置distributionManagement元素,需要同时配置repositorysnapshotRepository,分别用于部署发布版本和快照版本。

代码语言:javascript
代码运行次数:0
运行
复制
<distributionManagement>
  <repository>
    <id>proj-release</id>
    <name>Release</name>
    <url>http://xxxxxxx</url>
  </repository>
  <snapshotRepository>
    <id>proj-snapshot</id>
    <name>Snapshot</name>
    <url>http://xxxxxxx</url>
  </snapshotRepository>
</distributionManagement>

仓库认证:通常发布构件需要私服的上传和发布权限,以nexus私服为例,默认发布账号是deployment,需要配置settings.xml中的servers结点,server id即仓库ID

代码语言:javascript
代码运行次数:0
运行
复制
<servers>
  <server>
    <id>releases</id>
    <username>deployment</username>
    <password>deployment123</password>
  </server>
  <server>
    <id>snapshots</id>
    <username>deployment</username>
    <password>deployment123</password>
  </server>
</servers>

4.5 构件在仓库中的存储

存储位置:groupId/artifactId/version/artifactId-version[-classifier].packaging

解析依赖的机制:

  1. 当依赖范围是system时,maven直接从本地文件系统解析
  2. 根据依赖的坐标计算构件路径,先尝试从本地仓库寻找
  3. 如果本地仓库中不存在,则遍历所有远程仓库(如果没有配置远程仓库,默认会查找中央仓库)
  4. 如果仓库配置了镜像,则从镜像仓库中查找
  5. 如果依赖的是RELEASE或LATEST或快照版本时,需要根据更新策略来检查是否有版本更新,如果有则将远程仓库中的构件更新到本地仓库

构件的最新版本信息存储于仓库的元数据 中(maven-metadata.xml) release构件元数据:groupId/artifactId/maven-metadata.xml snapshot构件元数据:groupId/artifactId/version/maven-metadata.xml

5 生命周期 Lifecycle

maven将软件生命周期进行了抽象,生命周期是相对固定的,由一组阶段(Phase) 组成,每个阶段绑定插件来完成相应任务。有点像设计模式中的模板方法(Template Method),maven定好了生命周期的主体框架,保证框架的一致性,但每个阶段又能灵活定制。

maven有三套生命周期,每个生命周期由一组有顺序的阶段(Phase)组成,后面的阶段依赖前面的阶段,三套生命周期之间互相独立。

clean生命周期

用于清理项目,有3个阶段组成:

  1. pre-clean
  2. clean:清除上次构建生成的文件(删除target目录)
  3. post-clean

default生命周期

用于构建项目,这个生命周期使用最多

  1. validate:校验项目必须的信息是否正确
  2. initialize
  3. generate-sources
  4. process-sources
  5. generate-resources
  6. process-resources:处理项目主资源文件。一般是将src/main/resources中的内容进行变量替换后复制到classpath中
  7. compile:编译源码,输出到classpath中
  8. process-classes
  9. generate-test-sources
  10. process-test-sources
  11. generate-test-resources
  12. process-test-resources
  13. test-compile
  14. process-test-classes
  15. test:使用单元测试框架运行测试,测试代码不会被打包或部署
  16. prepare-package
  17. package:将编译好的代码打包成可发布的格式
  18. pre-integration-test
  19. integration-test
  20. post-integration-test
  21. verify:基于集成测试的结果进行检查以确保质量标准
  22. install:将包安装到本地仓库,提供给本地其他项目使用
  23. deploy:将包部署到远程仓库,供其他项目使用

site生命周期

用于建立项目站点,一般很少使用,有以下4个阶段组成

  1. pre-site
  2. site:生成项目站点文档
  3. post-site
  4. site-deploy:将生成的项目站点发布到服务器上

maven生命周期参考文档:http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

maven允许直接调用阶段,如mvn clean install site,因三个生命周期相互独立,所以可以同时调用。

6 插件 Plugin

maven通过在生命周期的阶段上绑定插件目标的方式,把具体任务交给插件来完成。

每个插件一般都会提供多个插件目标(Goal) ,例如前文提到的dependency插件就有listtreeanalyze等goal, 以及maven-compiler-plugin插件提供的compilegoal,把goal与阶段绑定即可实现对插件的调用。

maven提供了一些阶段和插件目标的内置绑定关系(https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Built-in_Lifecycle_Bindings)可以应对绝大多数日常使用,因此调用mvn compile实际上是调用的maven-compiler-plugin插件的compilegoal。

插件的目标也可以直接调用,即使用mvn 插件名:目标的方式,例如上面提到的mvn dependency:list。但直接调用目标就脱离了maven的生命周期,一般只用于一些工具类的插件。

插件的默认绑定阶段

有一些插件的目标在编写时会绑定到默认阶段,例如上面提到的compile就是默认绑定的。

使用maven-help-plugin插件来查看其它插件的详细信息以及默认绑定信息(help插件和被查询的插件都要在工程里声明),命令:

代码语言:javascript
代码运行次数:0
运行
复制
mvn help:describe -Dplugin=org.apache.maven.plugins:maven-source-plugin:2.1.1 -Ddetail

自定义绑定阶段

例如,把maven-help-plugin插件的describe目标绑定到verify阶段上(只是举个例子,一般不会这么绑定):

代码语言:javascript
代码运行次数:0
运行
复制
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-help-plugin</artifactId>
      <version>2.2</version>
      <executions>
        <execution>
          <id>help</id>
          <phase>verify</phase>
          <goals>
            <goal>describe</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

插件groupId可以省略

有些项目中会看到引入插件并没有配置groupId,那是因为maven内置了两个groupId:org.apache.maven.pluginsorg.codehaus.mojo,即这两个groupId可以省略不写。

在settings.xml中的pluginGroups可以配置额外的插件groupId

另,插件的元数据比较特殊,存储于groupId/maven-metadata.xml中

7 模块 Module

开发maven项目,通常都不会是单模块项目,其最佳实践是新建一个父模块,packaging设置为pom,并在父模块POM文件中配置modules,如:

代码语言:javascript
代码运行次数:0
运行
复制
<groupId>com.xxx</groupId>
<artifactId>yyy</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
  <module>yyy-controller</module>
  <module>yyy-service</module>
</modules>

每个module既是子模块,又是一个与当前pom的同级目录,添加子模块后,只需构建顶级模块,子模块会同时构建

7.1 模块的继承

子模块的好处:

  1. 可以一个命令构建完整个项目,而不必每个模块都单独构建
  2. 子模块可继承父模块的POM元素

能够被继承的元素有:

  • groupId
  • version
  • description
  • organization
  • inceptionYear:项目创始年份
  • url:项目的URL地址
  • developers:开发者
  • contributors:贡献者
  • distributionManagement:项目部署配置
  • issueManagement:项目缺陷跟踪系统信息
  • ciManagement:项目持续集成系统信息
  • scm:项目版本控制系统信息
  • mailingLists:项目邮件列表
  • properties:自定义maven属性
  • dependencies:依赖配置
  • dependencyManagement:依赖管理配置
  • repositories:仓库配置
  • build:构建配置,包括源码目录、输出目录、插件、插件管理

任何maven项目都隐式继承超级POM,类似Java的Object。超级POM位置:$MAVEN_HOME/lib/maven-model-builder-x.x.x.jar中的org/apache/maven/model/pom-4.0.0.xml

一些元素说明:dependencyManagement:该元素下的依赖声明不会引入实际的依赖,只是把声明继承给子模块,子模块在配置依赖时只需配置groupId和artifactId即可,未配置的属性(version、scope等)都从dependencyManagement中继承。

pluginManagement:与dependencyManagement类似

7.2 构建反应堆

如果把多模块maven项目中的所有模块的依赖关系用图来表示,这个图结构即为构建反应堆(Reactor) 。反应堆应该是一个有向非循环图,如果模块间出现循环依赖则会报错。

反应堆的构建顺序:

  1. 按声明顺序构建;
  2. 如果一个模块依赖与另一个模块,先构建被依赖模块。

裁剪反应堆:有些项目非常大,构建时可以选择只构建某些模块以提高构建速度,通过在mvn命令中指定以下参数可以对反应堆进行裁剪。

代码语言:javascript
代码运行次数:0
运行
复制
-pl p1 [,p2 ,p3 ......]    选择指定模块
-am        also make,同时构建所选模块的依赖模块
-amd       also make dependecies,同时构建依赖于所选模块的模块

8 测试 Test

maven的default生命周期中有一个test阶段专门用于执行单元测试,默认单元测试插件:maven-surefire-plugin,绑定目标test

该插件会自动检测src/test/java下以Test开头的类、以Test结尾的类、以TestCase结尾的类用于执行单元测试。在插件的includesexcludes,可以配置额外包含或排除的测试类。

使用命令mvn test -Dtest=测试类名可以只测试某个类

使用-DskipTests-Dmaven.test.skip=true参数可以跳过单元测试

生成测试覆盖率报告(与其他报告相同,输出在site目录下) 使用到插件:cobertura-maven-plugin

9 站点 Site

这里的站点是指包含本项目信息的一些静态界面,包括项目的基本信息、依赖信息、测试报告、代码检查报告等,maven支持在构建的过程中同时对这些信息进行输出。

9.1 生成站点

使用mvn site命令可以将项目信息生成站点到target/site

针对多模块项目,可能更希望把所有模块的信息汇总一个目录,可以使用mvn site:stage,默认汇总到target/staging,但必须先执行mvn site

在站点中增加静态检查报告:(findbugs必须先package生成classes)

代码语言:javascript
代码运行次数:0
运行
复制
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-site-plugin</artifactId>
  <version>3.5.1</version>
  <configuration>
    <locales>zh_CN</locales>
    <reportPlugins>
      <reportPlugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-checkstyle-plugin</artifactId>
        <version>2.17</version>
        <configuration>
          <configLocation>mucfc-checkstyle-1.0.xml</configLocation>
        </configuration>
      </reportPlugin>
      <reportPlugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-pmd-plugin</artifactId>
        <version>2.7.1</version>
        <configuration>
          <targetJdk>${jdk.version}</targetJdk>
        </configuration>
      </reportPlugin>
      <reportPlugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>findbugs-maven-plugin</artifactId>
        <version>3.0.4</version>
      </reportPlugin>
      <!-- 在报告中查看源码插件 -->
      <reportPlugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jxr-plugin</artifactId>
        <version>2.5</version>
      </reportPlugin>
    </reportPlugins>
  </configuration>
</plugin>

自定义生成其他项目信息:

代码语言:javascript
代码运行次数:0
运行
复制
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-project-info-reports-plugin</artifactId>
  <version>2.9</version>
  <reportSets>
    <reportSet>
      <reports>
        <report>dependencies</report>
      </reports>
    </reportSet>
  </reportSets>
</plugin>

report可配置如下值:

  • cim:持续集成报告
  • dependencies:项目依赖报告
  • dependency-convergence:依赖聚合报告(分析依赖问题)
  • dependency-info:为其他构建工具生成本项目的依赖代码片段(方便复制,没什么用)
  • dependency-management:依赖管理报告
  • distribution-management:分发管理报告
  • help:生成帮助文档
  • index:生成首页
  • issue-tracking:问题跟踪管理报告
  • license:生成证书报告
  • mailing-list:邮件列表
  • modules:模块
  • plugin-management:插件管理
  • plugins:插件
  • project-team:项目成员
  • scm:项目源码管理报告
  • summary:摘要

9.2 发布站点

使用mvn site-deploy命令可以生成站点,并部署到远程服务器。

把站点部署到本地文件系统:

代码语言:javascript
代码运行次数:0
运行
复制
<distributionManagement>
    <site>
        <id>site</id>
        <url>file:E:\\site</url>
    </site>
</distributionManagement>
部署到远程(远程服务器需要安装ssh)
代码语言:javascript
代码运行次数:0
运行
复制
<distributionManagement>
    <site>
        <id>stagingSite</id>
        <url>scp://192.168.0.100/home/report/test</url>
    </site>
</distributionManagement>

10 属性 Property

在maven pom文件中可以通过${}来引用属性,属性分为以下几类

内置属性

${basedir}:项目根目录,pom所在目录

POM属性

可以引用POM文件中对应元素的值,如${project.groupId}对应project->groupId的值

  • ${project.build.sourceDirectory}:源码目录,默认src/main/java
  • ${project.build.testSourceDirectory}:测试源码目录,默认src/test/java、
  • ${project.build.directory}:项目构建输出目录,默认target/
  • ${project.outputDirectory}:项目主代码编译输出目录,默认target/classes/
  • ${project.testOutputDirectory}:测试编译输出目录,默认target/test-classes/
  • {project.build.finalName}:打包输出的文件名,默认{project.artifactId}-

settings属性

以settings开头,引用settings.xml中的元素

如${settings.localRepository}:本地仓库地址

Java系统属性

如${user.home}

环境变量属性

以env.开头,如${env.JAVA_HOME}

自定义属性

在pom的properties结点中定义的属性

Java系统属性和环境变量属性都可以用mvn help:system查看

在springboot中,properties文件中可以通过@xxx@直接引用pom属性

11 一些最佳实践

11.1 配置编码格式

代码语言:javascript
代码运行次数:0
运行
复制
<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <jdk.version>1.8</jdk.version>
  <maven.compiler.source>1.8</maven.compiler.source>
  <maven.compiler.target>1.8</maven.compiler.target>
</properties>

11.2 版本号约定

版本号:主版本.次版本.增量版本-里程碑版本。 如2.0.1-alpha-1,3.1.0-release。 增量版本和里程碑版本可以省略。

通常快照版本以-SNAPSHOT结尾

11.3 父子工程版本号保持一致

一般父工程pom定义如下:

代码语言:javascript
代码运行次数:0
运行
复制
<groupId>com.xxx</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>

子工程pom定义:

代码语言:javascript
代码运行次数:0
运行
复制
<parent>
  <groupId>com.xxx</groupId>
  <artifactId>parent</artifactId>
  <version>1.0.0</version>
</parent>
<artifactId>child</artifactId>

这样子工程可以与父工程保持一致的版本,但有个问题是子工程需显式引用父工程的版本号,每次版本变更时需要把所有子工程的parent-version字段同时更新一遍。

在maven3.5以后提供了对revision的支持,可以让项目版本号只需配置一次。

父工程定义:

代码语言:javascript
代码运行次数:0
运行
复制
<groupId>com.xxx</groupId>
<artifactId>parent</artifactId>
<version>${revision}</version>

<properties>
  <revision>1.0.0</revision>
</properties>

子工程定义:

代码语言:javascript
代码运行次数:0
运行
复制
<parent>
  <groupId>com.xxx</groupId>
  <artifactId>parent</artifactId>
  <version>${revision}</version>
  <relativePath>../pom.xml</relativePath>
</parent>
<artifactId>child</artifactId>

END

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-11-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 支付进阶之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • clean生命周期
  • default生命周期
  • site生命周期
    • 部署到远程(远程服务器需要安装ssh)
  • 内置属性
  • POM属性
  • settings属性
  • Java系统属性
  • 环境变量属性
  • 自定义属性
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档