Maven 继承、聚合、属性

news2024/11/24 18:47:55

文章目录

  • 一、继承
    • 1.1. 概念
    • 1.2. 语法
    • 1.3. 示例
    • 1.4. 其他常见使用
  • 二、聚合
    • 2.1. 概念
    • 2.2. 示例
  • 三、属性
    • 3.1. Java 系统属性
    • 3.2.系统环境变量属性
    • 3.3.Maven 内置属性

一、继承

1.1. 概念


当项目较大,为了便于开发和管理,经常需要将工程划分成多个 Maven 工程(这些 Maven 工程此时被称为模块),这时模块间很可能会相互依赖,而每个模块的依赖信息都是模块单独管理,所以很可能导致依赖冲突,如下图:

模块间依赖冲突

很明显上图中,Lombok 模块发生了依赖冲突,虽然这种情况 Maven 仲裁机制会自动帮我们判定留下的版本是 Service 模块中的 Lombok 1.10.0,但如果 Dao 模块引用 Lombok 1.18.8 的目的就是为了使用 1.18.8 的新特性,这个时候就会有问题,因为最后留下来的版本 1.10.0 并不具备新特性

为了避免上述问题的发生,所以不建议在各个模块中单独管理依赖的版本信息,建议用一个专门的工程来统一管理依赖的版本,通常的情况下,所谓父工程,就是这个专门做依赖版本信息管理的工程

不只是多模块的场景适合父工程,建议每个公司都要有自己的一个公司级别的父工程,在工程中将多年总结下来的依赖间的版本搭配定义下来,之后有新项目启动时,都来继承这个父工程,减少版本兼容性的试验,


1.2. 语法


使用父工程来管理依赖版本,一共就两步:

  1. 父工程中指定 <packaging>pom</packaging>,并在 <dependencyManagement> 节点下声明各个依赖的版本信息
  2. 子模块中通过 <parent> 声明父工程的 GAV,之后依赖引用时不再需要 <version> 信息

1.3. 示例


(1)先定义一个父工程,其 pom.xml 如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<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.ares5k</groupId>
  <artifactId>ares5k-parent</artifactId>
  <version>1.0-SNAPSHOT</version>

  <!--  修改打包方式 -->
  <packaging>pom</packaging>

  <!-- 管理依赖的版本 -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.8</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

<dependencyManagement> 节点下声明的依赖信息,并不会真正的将依赖引用进来,这里只是声明依赖版本而已


(2)再定义一个子模块,其 pom.xml 如下:

<?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>

  <!-- 工程坐标 -->
  <artifactId>ares5k-module</artifactId>

  <!-- 指定父工程坐标-->
  <parent>
    <groupId>com.ares5k</groupId>
    <artifactId>ares5k-parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <relativePath>../ares5k-parent/pom.xml</relativePath>
  </parent>

  <!-- 引入 lombok 依赖,不需要指定 version 信息 -->
  <dependencies>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>
  </dependencies>
</project>

详细说明:

  • 当子模块的 <groupId><version> 与父工程相同时,在子模块中就可以将子模块的 <groupId><version> 省略

  • <relativePath> 用相对路径指定父工程 pom.xml 文件的位置,如果父工程已经安装在本地或远程仓库中,那么 <relativePath> 可以省略,<relativePath> 声明时,其寻找父工程的路径为 relativePath -> 本地仓库 -> 远程仓库

  • 子模块 <dependencies> 中的声明才是真正的把依赖引入进来,子模块如果不主动引入依赖,那么父工程 <dependencyManagement> 节点下声明的依赖就不会被真正的引入

1.4. 其他常见使用


在父工程中,除了管理依赖的版本,也经常用来管理生命周期插件、自定义属性、部署仓库、远程仓库等

自定义属性

自定义属性的使用方式:在 <properties> 下自定义节点,节点内的数据就属性值,定义后不管是父工程还是子模块,直接通过 ${自定义节点名} 就可以直接访问自定义属性

<!-- 声明自定义属性 -->
<properties>
  <ares5k-lombok-version>1.18.8</ares5k-lombok-version>
  <ares5k-jar-plugin>3.0.2</ares5k-jar-plugin>
</properties>
<!-- 使用自定义属性 -->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>${ares5k-lombok-version}</version>
</dependency>

部署仓库 <distributionManagement> 和 远程仓库 <repositories> 在父工程声明后,子模块会直接继承该配置,不需要再声明。生命周期插件管理 <pluginManagement>,网上很多人说它和 <dependencyManagement> 一样,在父工程中声明后,如果子模块不主动引入,那么子模块就不会应用父工程 <dependencyManagement> 中配置的插件,这个说法,我测试是不正确的,最起码在 Maven 3.6.3 版本中不是这样的,只要在父工程 <dependencyManagement> 中声明了插件,不管子模块是否主动引入,在执行生命周期插件时,都会应用父工程中配置的插件


二、聚合


2.1. 概念

当有很多 Maven 工程都需要执行生命周期命令时,如果一个一个执行很浪费时间,所以可以通过创建一个聚合工程,将所有的 Maven 工程聚合到一起,然后统一执行命令

聚合

2.2. 示例

聚合工程就是一个普通的 Maven 工程,只不过需要设置 <packaging>pom</packaging>,然后在 <modules> 节点中将子模块目录的相对路径添加进来即可,<module> 中不是子模块的 <artifactId> 而是其与聚合工程的相对路径

<packaging>pom</packaging>
<modules>
  <module>../ares5k-module-test</module>
  <module>ares5k-module-inner</module>
</modules>

<modules> 添加好后就可以在聚合工程的 pom.xml 路径下运行生命周期命令,来统一构建

统一构建

到这里可能会发现聚合工程和继承用的父工程颇有相似的地方:

  1. 都需要创建一个单独的工程
  2. 都需要设置 <packaging>pom</packaging>

所以当既需要父工程又需要聚合工程的时候,为了避免冗余创建,基本都是只创建一个工程就可以,然后在该工程的 pom.xml 中将 <modules><dependencyManagement> 等节点都添加进去。这种做法尤其适合一个项目分为多个模块的场景,但是公司级的父工程还是比较适合单独创建

下图为我个人比较喜欢的 Maven 结构:
喜欢的Maven结构


三、属性


我们除了可以在 pom.xml 中使用自定义属性,也可以使用已有属性,已有属性大概分为:Java 系统属性、系统环境变量属性、Maven 内置属性

3.1. Java 系统属性

Java 系统属性包括:Java 默认的系统属性、运行 Java 程序时传入的虚拟机参数、Java 程序中自定义的系统属性,其使用语法很简单,就是 ${Java系统属性名}

打印 Java 系统属性列表

如果不知道 Java 系统属性都有什么,可以通过下面 Java 代码打印一下:

package com.ares5k;

import java.util.Properties;
import java.util.Set;

public class App {
    public static void main(String[] args) {
        Properties properties = System.getProperties();
        Set<Object> propNameSet = properties.keySet();
        for (Object propName : propNameSet) {
            String propValue = properties.getProperty((String) propName);
            System.out.println(propName + " = " + propValue);
        }
    }
}

运行上面代码后,会有类似如下结构的输出,= 左边的就是 Java 系统属性名,右边的是 Java 系统属性值,假如在 pom.xml 中使用 ${java.runtime.name},在 pom 文件运行时,就会将内容替换成 Java(TM) SE Runtime Environment

java.runtime.name = Java(TM) SE Runtime Environment
sun.boot.library.path = D:\java8\jre\bin
java.vm.version = 25.251-b08
java.vm.vendor = Oracle Corporation
java.vendor.url = http://java.oracle.com/
path.separator = ;
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
file.encoding.pkg = sun.io
user.country = CN

3.2.系统环境变量属性

系统环境变量就是我们在操作系统中设置的环境变量,以 Windows 为例,下图就是系统变量,在 pom.xml 中通过语法 ${env.全大写系统变量名} 的方式就可以使用系统环境变量值,以下图中系统变量 ComSpec 为例,应该写成 ${env.COMSPEC}

Win系统变量


3.3.Maven 内置属性

除了能获取 Java 系统变量、操作系统环境变量,Maven 还提供了内置的属性

(1)访问 Pom 文件的节点

通过 ${project.标签名}${project.父标签.子标签} 可以访问 pom.xml 中的节点,不只可以访问当前工程 pom.xml 中的节点,超级 Pom 中的节点也可以访问

测试后,发现并不是所有的节点都能访问,列举一些我实验可用的:

属性说明
${project.basedir}项目在磁盘的全路径
${project.packaging}项目的打包方式
${project.groupId}项目的 groupId
${project.artifactId}项目的 artifactId
${project.version}项目的 version
${project.parent.groupId}父工程的 groupId
${project.parent.artifactId}父工程的 artifactId
${project.parent.version}父工程的 version
${project.parent.relativePath}到父工程目录的相对路径
${project.build.finalName}Maven 执行 package 阶段后的包名
${project.build.directory}构建后的输出目录
${project.build.sourceDirectory}源程序的目录
${project.build.outputDirectory}源程序编译后的输出目录
${project.build.testSourceDirectory}测试源程序的目录
${project.build.testOutputDirectory}测试源程序编译后的输出目录
${project.distributionManagement.repository.url}远程部署仓库中发版库的 URL
${project.distributionManagement.snapshotRepository.url}远程部署仓库中快照库的 URL

(2)访问Settings 文件的节点

通过 ${settings.标签名}${settings.父标签.子标签} 可以访问 Maven 安装目录/conf/settings.xml 中的节点,跟访问 Pom 文件一样,并不是所有节点都能成功访问,但是感觉 settings.xml 文件中没啥好总结的,就这样吧,就不列出了

(3)时间戳

可以通过 ${maven.build.timestamp} 获取当前时间,一般常用在打包后设置包名

如果对时间格式不满意,可以添加如下属性
<maven.build.timestamp.format>自定义时间格式</maven.build.timestamp.format> 来修改时间格式:

<!-- 自定义时间格式 -->
<properties>
  <maven.build.timestamp.format>yyyy-MM-dd</maven.build.timestamp.format>
</properties>
<!-- 自定义包名 -->
<build>
  <finalName>${project.artifactId}-${project.version}-${maven.build.timestamp}</finalName>
</build>

修改后通过 ${maven.build.timestamp} 就可以获取目标格式的自定义时间了,但是有一点要注意的是,通过这种方式获取的时间的时区是 UTC,并且无法修改时区,如果想修改时区,我们就不能用 ${maven.build.timestamp} 这种方式来获取时间,而是需要引入一个生命周期插件,代码如下:

<build>
  <plugins>
    <!-- 引入插件 -->
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>build-helper-maven-plugin</artifactId>
      <version>3.3.0</version>
      <executions>
        <execution>
          <goals>
            <goal>timestamp-property</goal>
          </goals>
          <configuration>
            <!-- 自定义名称,后面输出日期时使用 -->
            <name>build.time</name>
            <!-- 设置日期格式 -->
            <pattern>yyyyMMddHHmmss</pattern>
            <!-- 设置时区 -->
            <timeZone>GMT+8</timeZone>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
  <!-- 设置打包名:artifactId + version + 上面设置的时间自定义名称 -->
  <finalName>${project.artifactId}-${project.version}-${build.time}</finalName>
</build>


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/766187.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【性能测试入门必看】性能测试流程简介

性能测试流程介绍&#xff1a; 一、性能测试流程&#xff08;一&#xff09;——问清性能测试需求 1、新系统能力验证 2、明确客户需求 3、找出系统性能瓶颈 4、稳定性验证&#xff08;强度测试&#xff09; 二、性能测试流程&#xff08;二&#xff09;——了解系统结构…

为什么C++支持函数重载

C语言中我们知道创建的函数是不能同名的&#xff0c;但是在C中却是可以的&#xff0c;这就是C中的函数重载&#xff0c;而函数重载有三种&#xff1a;函数参数类型不同、参数的数量不同、参数的顺序不同。所以就先浅浅的了解一下函数重载&#xff1a; 函数重载 参数类型不同 …

数据管道模型:场外流式数据市场形态探索

数据管道模型&#xff1a;场外流式数据市场形态探索 任洪润1,2, 朱扬勇1,2 1 复旦大学计算机科学技术学院&#xff0c;上海 200438 2上海市数据科学重点实验室&#xff0c;上海 200438 摘要&#xff1a;当前数据要素市场建设探索主要集中在数据交易场所&#xff08;场内&#x…

ubuntu18.04配置python虚拟环境

安装virtualenv 在机器上使用pip安装virtualenv pip install virtualenv创建虚拟环境 cd 到一个目录中创建虚拟环境 virtualenv 虚拟环境名 如 virtualenv venv 激活虚拟环境 在虚拟环境路径中执行source 加载activate source bin/activate结果如下&#xff1a;

【基于 GitLab 的 CI/CD 实践】02、gitlab-runner 实践

目录 一、gitlab-runner 简介 1.1 要求 1.2 特点 二、GitLab Runner 安装 2.1 使用 GItLab 官方仓库安装 2.2 使用 deb/rpm 软件包 2.3 在容器中运行 GitLab Runner 三、GitLab Runner 注册 3.1 GitLabRunner 类型 3.2 获取 runner token 获取 shared 类型 runner t…

Linux驱动之从点LED灯开始

目录 一、环境 二、Linux 下 LED 灯驱动原理 2.1 地址映射 2.2 I/O 内存访问函数 三、硬件原理图分析 四、实验程序编写 4.1驱动程序编写 4.2测试APP编写 五、编译驱动程序和测试 APP 5.1 编译驱动程序 5.2 编译测试 APP 六、测试 本期的内容到这就结束了&#xff…

Ubuntu下的rdate命令

介绍 用途&#xff1a;rdate命令的用途是从远程服务器上同步时间并设置到本地。 安装rdate 执行命令sudo apt install rdate进行安装&#xff1a; 查看rdate命令的帮助信息 执行命令man rdate&#xff0c;可以查看rdate的帮助信息&#xff1a; 示例 从远程服务器上同…

基于opencv对高空拍摄视频消抖处理

一、问题背景 无人机在拍摄视频时&#xff0c;由于风向等影响因素&#xff0c;不可避免会出现位移和旋转&#xff0c;导致拍摄出的画面存在平移和旋转的帧间变换&#xff0c; 即“抖动” 抖动会改变目标物体 (车辆、行人) 的坐标&#xff0c;给后续的检测、跟踪任务引入额外误差…

Html基础知识学习——圣杯布局、margin负值、等高布局(十七)

文章目录 圣杯布局margin负值等高布局 圣杯布局 两边页面固定中间页面宽度随着浏览器大小自适应 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-widt…

macOS - 安装 node、npm

文章目录 关于 node安装安装 node、npm 关于 node node.js 官网 : https://nodejs.org/engithub : https://github.com/nodejs Node.js is a free, open-sourced, cross-platform JavaScript run-time environment— that lets developers write command line tools and serv…

使用QTableWidget实现录像排程操作

一、介绍 该录像排程&#xff0c;是采用继承于QTableWidget的ScheduleTableWidget类进行实现。在ScheduleTableWidget实现类中&#xff0c;去除了Table原本的横向表头和纵向表头&#xff0c;分别采用第一行和第一列构成新的表头。新的横向表头代表一天24小时&#xff0c;新的纵…

CMake基础入门

文章目录 一、一个目录下有一个源文件&#xff08;入门&#xff09;1.1 预定义的变量1.2 语法介绍cmake_minimum_requiredprojectsetmessageadd_executable 1.3 最基础的实例1.4 第一步优化&#xff1a;build目录实操流程 1.5 第二步优化&#xff1a;src目录1.5.1 实操流程1.5.…

用心做好一款堡垒机,升级版《新一代堡垒机建设指南》白皮书现已开放下载!

编者注&#xff1a;本文刊登在《新一代堡垒机建设指南》&#xff08;JumpServer v3.0发布纪念版&#xff09;序言部分&#xff0c;文章作者为JumpServer开源堡垒机项目创始人广宏伟。点击文章底部“阅读原文”链接&#xff0c;即可下载新版《新一代堡垒机建设指南》白皮书。 “…

Vue3 – 实现过渡动画

1 认识Vue的动画原理 2 动画中常见类的作用 3 animation动画实现 4 动画的常见属性设置 5 列表元素动画组实现 6 列表元素的移动动画 认识Vue的动画原理 利用transition标签和一系列的动画类来控制标签的动画效果。 transition标签的本质是帮你添加和删除动画类的。 trans…

SpringBoot整合EasyExcel实现读操作

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; SpringBoot整合EasyExcel实现读操作 ⏱️ 创作时间&#xff1a; 2023年…

linux中的sendmail发送邮件

Linux/UNIX 下的老牌邮件服务器。 Sendmail 作为一种免费的邮件服务器软件&#xff0c;已被广泛的应用于各种服务器中&#xff0c;它在稳定性、可移植性、及确保没有 bug 等方面具有一定的特色&#xff0c;且可以在网络中搜索到大量的使用资料。 一、邮件发送原理图 MUA&#x…

通过弹性算力支持与托管式机器学习服务,亚马逊云科技为客户提升技术竞争力

时下数字化浪潮中&#xff0c;生成式人工智能&#xff08;AIGC&#xff09;已成为企业实现业务增长和数字化转型的重要技术&#xff0c;为企业提供了重新定义和调优业务模式的机遇。越来越多的企业希望利用人工智能技术提升竞争力&#xff0c;应对复杂的商业环境和市场挑战&…

机器学习实战:Python基于Ridge岭回归进行正则化(十三)

文章目录 1.前言1.1 岭回归的介绍1.2 岭回归的应用 2.自定义数据集实战演示2.1 导入函数2.2 创建数据集2.3 alpha0、1、10、100的分别情况 3.Dushanbe_house数据集实战演示3.1 导入函数和数据3.2 剔除空值及可视化3.3 整理数据3.4 训练和测试数据集3.5 评估数据集 4.讨论 1.前言…

mysql更新关联字段问题

现象 ### 表结构 CREATE TABLE wjf_test_update_num (id bigint(20) NOT NULL AUTO_INCREMENT,num1 int(11) DEFAULT NULL,num2 int(11) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT3 DEFAULT CHARSETutf8 |## 插入两行数据 insert into wjf_test_update_nu…

从源码理解Scala中函数reduceRight的计算过程

水善利万物而不争&#xff0c;处众人之所恶&#xff0c;故几于道&#x1f4a6; 以List集合为例&#xff0c;进行reduceRight()的计算过程分析&#xff0c;总体分为两部分&#xff0c;一部分是看最顶层特质的那个通用的reduceRight方法&#xff0c;另一部分是讲直接混入的特质的…