从0到0.1学习 maven(三:声明周期、插件、聚合与继承)

news2024/11/27 21:04:49

该文章为maven系列学习的第三篇,也是最后一篇
第一篇快速入口:从0到0.1学习 maven(一:概述及简单入门)
第二篇快速入口:从0到0.1学习 maven(二:坐标、依赖和仓库)

文章目录

  • 啥子叫生命周期
  • 生命周期详解
    • clean生命周期
    • default生命周期
    • site生命周期
  • 插件
    • 插件配置
    • 插件解析
    • 聚合
    • 继承
      • 可继承的元素
      • 依赖管理
      • 插件管理
    • 小结
    • 反应堆
      • 裁剪反应堆

啥子叫生命周期

构建步骤包括项目清理,初始化,编译,测试,打包,集成测试,验证,部署等等。maven将这些过程进行了抽象与统一,映射到了生命周期上。
可以将maven的生命周期理解成设计模式中的模板方法。父类定义整体结构,子类进行具体方法的实现和重写。在控制整体结构的同时也增加了可拓展性。maven没有对这些步骤提供实现,但是提供了默认绑定的插件,因此实际上每个步骤都是通过插件完成的。

生命周期详解

实际上,maven中的生命周期分成了三套,分别为clean,default与site,分别对应着 清理,构建与建立项目站点。每套生命周期都对应着一些有序的阶段。等下会详细介绍。三套生命周期本身是相互独立的,也就是调用clean不会影响到site。

clean生命周期

阶段1:pre-clean: 执行清理前需要完成的工作
阶段2:clean:清理上一次构建生成的文件
阶段3:post-clean:执行一些清理后需要完成的工作
阶段间是有序的,因此若想调用post-clean,会按preclean-clean-postclean的顺序执行。

default生命周期

在default周期中,定义了真正构建时需要的步骤。官方介绍可以参考:https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

  • validate:验证项目是否正确,所有需要的信息是否都可用
  • initialize:初始化例如属性的设置、 目录的创建等
  • generate-sources:
  • process-sources:处理项目主资源文件,一般是在src/main/resources中,完成变量替换等,再复制到项目输出的主classpath目录中。
  • generate-resources
  • proess-resources
  • compile:编译源代码,一般是在src/main/java目录下
  • process-classes
  • generate-test-sources
  • process-test-sources:处理测试资源文件。一般是在src/test/resources目录下,将该目录下的java文件编译输出到测试的classpath目录中。
  • generate-test-resources
  • process-test-resources
  • test-compile:编译项目的测试代码。一般在src/test/java目录下。编译好后输出到测试的classpath目录中。
  • process-test-classes
  • test:用单元测试框架来测试编译后的源代码,测试代码不会打包或者部署。
  • prepare-package
  • package:用指定的后缀格式将编译后的代码进行打包
  • pre-integration-test
  • integration-test
  • post-integration-test
  • verify
  • install:将package安装到本机的仓库中,以供其他依赖它的项目使用
  • deploy:将最终的package复制到远程仓库中,以供其他开发者与项目共享

site生命周期

该周期的主要作用为建立和发布项目站点。根据pom中包含的信息,自动生成站点。

  • pre-site:完成一些生成项目站点之前需要的工作
  • site:生成项目站点文档
  • post-site:完成一些生成项目站点之后的工作
  • site-deploy:将生成的项目站点发布到服务器上。

插件

首先介绍一下插件目标,可以将一个小功能点理解成一个目标。前面提到核心功能都是通过插件的形式来实现的,但是针对一个功能点就开发一个插件显然会有很多冗余代码。因此一个插件可能会包含多个插件目标。

生命周期会与插件相互绑定,例如对于A过程, 插件B可以完成该任务,因此将AB进行绑定。如果某过程没有绑定插件,那该过程就不会有实际行为。
为了让用户几乎不用配置就可以构建maven项目,maven会对主要的生命周期阶段进行内置的插件绑定。
另外,一个插件也可以绑定多个阶段,例如clean生命周期的三个阶段都绑定在了maven-clean-plugin:clean插件上。

除了内置的绑定之外,用户也可以对阶段使用的插件进行自定义的绑定。

举一个自定义绑定插件的例子

<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-source-plugin</artifactId>
			<version>2.2.1</version>
			<executions>
				<execution>
					<id>attach-sources</id>
					<phase>verify</phase>
					<goals>
						<goal>jar</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>

可以看到,在execution元素下,指定了phase(阶段)和goal(目标)。

尝试删除phase阶段,再次执行mvn verfify,执行依然成功。因为很多插件的目标在编写的时候已经默认绑定了阶段。可以通过mvn help:describe -Dplugin=xxxxx -Ddetail来查看具体信息

运行mvn help:describe -Dplugin=org.apache.maven.plugins:maven-source-plugin:2.2.1 -Ddetail看一下我们刚刚用的包的细节。
在这里插入图片描述
第五行:Bound to phase: package 指明了他绑定的默认生命周期阶段时package。

ps: 如果不加版本号,则自动获取最新的版本。加了detail是为了更详细的信息。如果仅仅想知道某个目标的信息,可以使用goal参数。

插件配置

命令行配置
maven沿用了java的命令行传参模式即“-D”
例如上述例子中 -Dplugin=xxx就表示着传递 名为plugin,值为xxx的参数。

POM中插件全局配置
对于很少或不会改变的参数,直接写死在pom文件中。
直接在version下面加一个configuration的子标签

<configuration>
	<source>1.5</source>
	<target>1.5</target>
</configuration>

POM中配置任务参数
还可以为某个插件任务配置特定的参数

<configuration>
	<tasks>
		<echo>I am a task</echo>
	</tasks>
</configuration>

插件解析

首先,需要了解一个插件前缀的概念。我们刚刚使用了mvn help:describe"实际上是maven-help-plugin插件的describe目标。这里help就是插件前缀,其结构是groupId:artifactId。复习一下,依赖仓库的路径groupId/artifactId/maven-metadata.xml,插件仓库的元数据是在groupId/maven-metadata.xml下的。

插件像构件一样,以坐标的形式存储在maven仓库中。
插件仓库的子元素配置和依赖仓库完全相同。

  <repositories>
    <repository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>

如果是maven的官方插件(groupId=org.apache.maven.plugins),则可以省略groupId配置。

对于核心插件,maven为它们在超级pom(所有maven项目的父pom)中预先设定了版本。因此核心插件可以不用指定版本。

对于非核心插件,类似于仓库的版本解析,插件也有元数据文件。maven遍历本地与远程插件仓库,找到lastest和release。maven2会使用latest,maven3会使用release。

聚合

实际项目中,可能是会由多个项目组合起来的,需要对每个项目进行打包构建。如果每次都一个一个地去模块对应的目录下构建那是相当麻烦。因此聚合,也叫多模块 就是在一个目录可以构建项目中的所有包。

首先需要创建出一个额外的模块,并写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.company.sc</groupId>
	<artifactId>demo</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>a_practise_demo</name>
	<description>用于练习聚合的项目</description>
	<modules>
		<module>module_name_1</module>
		<module>module_name_2</module>
		<module>module-name-3</module>
    </modules>
</project>

它与普通的模块有三处不同

  1. packaging的值为pom,这标志着该模块为聚合模块。对其需要打包的子模块,都遵照各模块的packaging类型。
  2. 多了一层modules,标记着该聚合模块包含哪些模块。值得注意的是这里module子标签实际上不是真正的模块名,而是模块的目录名。因此如果这个聚合模块不是其他模块的父文件夹的话,需要将module元素的内容改成能指向正确模块的目录。
  3. 实际上,该聚合模块只会包含一个pom.xml文件,不会有test或java目录和代码。它仅仅是帮助构建的工具,并没有实际的内容。

继承

在maven世界里也有继承这个概念。像聚合一样,需要单独抽出一个目录,编写父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.company.sc</groupId>
	<artifactId>demo-parent</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>a_practise_demo</name>
</project>

它与聚合有两点相同:

  1. 除了pom之外没有其他目录
  2. packaging使用的也是pom

继承父类的子模块需要加入如下内容

<parent>
	<groupId>com.company.sc</groupId>
	<artifactId>demo-parent</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<relativePath>../dir1/dir2/pom.xml</relativePath>
</parent>

groupId, artifactId, version 是定义坐标系的三个最基本的元素,是必须的。relativePath表示父pom的相对路径,默认值是…/pom.xml,也就是maven默认父pom在上一层目录下。

另外,如果有聚合模块的话,该继承模块也需要被添加到modules标签下。

可继承的元素

  • groupId
  • version
  • description
  • organization
  • inceptionYear:项目的创建年份
  • url:项目的url地址
  • developers
  • contributors
  • distributionManagement:项目的部署配置
  • issueManagement:项目的issue信息
  • ciManagement:项目的持续集成系统信息
  • scm:项目的版本控制系统信息
  • mailingLists
  • properties:自定义maven属性
  • dependencies:项目的依赖配置
  • dependencymanagement:项目的依赖管理配置
  • repositories:项目的仓库配置
  • build:包括项目的源码目录配置、输出目录配置、插件配置等
  • reporting:包括项目的报告输出目录配置,报告插件配置等

依赖管理

父类的依赖可以被子类继承,但不一定所有的父类依赖都会被每个子类使用。这里maven提供了dependencyManagement元素,能让子模块继承到父模块的依赖配置,又能保证灵活性。因为dm元素下的依赖声明不会引入实际的依赖,但却能控制依赖。比如可以在父pom中声明依赖的groupId, artifactId, version,scope,子模块中就只需要groupId, artifactId,其他都可以从父类中继承。

依赖范围import只在dependencyManagement中才有效果。它的作用是将某pom中dm标签下的配置导入并合并到当前pom的dm元素中。假设另外一个模块想要导入我们前面的父类pom,可以通过以下配置。

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>com.company.sc</groupId>
			<artifactId>demo-parent</artifactId>
			<version>1.0.0-SNAPSHOT</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

一般import都会指向打包类型为pom的模块,因此type元素的值为pom。

插件管理

类似于刚刚的依赖管理,插件相应地也可以使用pluginManagement进行管理:在父pom中配置plugin元素,当子pom中继承并配置了对应地groupId和artifactId,pm中的配置才会生效。

小结

对于聚合模块,它知道有哪些被聚合的模块,但是被聚合的模块不知道它。对于继承模块,继承该模块的子模块知道他,但是他不知道都有谁继承了他。两个关系刚好相反,但是配置的时候packaging都必须是pom。在实际项目中,一个pom可能又当聚合pom又当父pom。

反应堆

反应堆指的是所有的模块形成的一个构建结构。拿以下模块为例子,该部分从demo的pom中提取。

<modules>
    <module>module_name_child_1</module>
    <module>module_name_father</module>
    <module>module_name_no_father</module>
</modules>

反应堆的构建顺序与声明顺序不一定一致,这个要取决于聚合与依赖关系。实际的构建顺序应为
demo->module_name_father->module_name_child_1->module_name_no_father
demo是聚合模块的起点,肯定是第一个构建的,然后按照顺序读取到了module_name_child_1,检查到它依赖着module_name_father,于是先去构建module_name_father。构建好了之后再构建module_name_father。接着继续按顺序,构建到module_name_no_father。一般来讲,依赖关系会将反应堆构建为有向无环图,如果有环,在构建时maven就会报错。

裁剪反应堆

如果想构建反应堆中的某些模块,可以使用mvn -h

  • -am (–also-make)同时构建所列模块的依赖模块
  • -amd(-also-make-dependens)同时构建 依赖于所列模块的模块
  • -pl(–projects )<args> 构建指定的模块,用逗号做分隔符
  • -rf(-resume-from)<args> 从指定的模块构建反应堆

举个例子,假设a依赖于b和c,如果用-am a的话,就会同时构建a b c。如果用-amd b的话,就会构建 a b。假设之前的构建顺序是 a b c d,那-rf c 就会构建c和d

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

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

相关文章

统计检验(一)// 方差分析

【应用案例】 检验不同组&#xff08;即不同收入者&#xff09;是否存在“品类满意度”显著差异。各组的满足度平均值如下&#xff1a; 【操作步骤】 方差分析的前提条件是各组总体方差没有显著差异。 第一步&#xff1a;方差同质性检验 原假设&#xff1a;没有差异。 结论…

接口测试入门,如何划分接口文档

1.首先最主要的就是要分析接口测试文档&#xff0c;每一个公司的测试文档都是不一样的。具体的就要根据自己公司的接口而定&#xff0c;里面缺少的内容自己需要与开发进行确认。 我认为一针对于测试而言的主要的接口测试文档应该包含的内容分为以下几个方面。 a.具体的一个业…

时间复杂度的计算(2023-02-10)

时间复杂度的计算 时间复杂度的计算分为三大类&#xff1a;一层循环、二层循环和多层循环。 一层循环 1.找出循环趟数t及每轮循环i的变化值 2.确立循环停止的条件 3.得出t与i之间的关系 4.联立两式&#xff0c;得出结果 eg: void fun(int n) {int i0;while (i*i*i<n)i;…

LeetCode刷题模版:292、295、297、299-301、303、304、309、310

目录 简介292. Nim 游戏295. 数据流的中位数297. 二叉树的序列化与反序列化【未理解】299. 猜数字游戏300. 最长递增子序列301. 删除无效的括号【未理解】303. 区域和检索 - 数组不可变304. 二维区域和检索 - 矩阵不可变309. 最佳买卖股票时机含冷冻期310. 最小高度树【未理解】…

测试开发,测试架构师为什么能拿50 60k呢需要掌握哪些技能呢

这篇文章是软件工程系列知识总结的第五篇&#xff0c;同样我会以自己的理解来阐述软件工程中关于架构设计相关的知识。相比于我们常见的研发架构师&#xff0c;测试架构师是近几年才出现的一个岗位&#xff0c;当然岗位title其实没有特殊的含义&#xff0c;在我看来测试架构师其…

产业互联网是对互联网的衍生和进化,也是一次重塑和再造

互联网并不仅仅只是充当撮合和中介的角色&#xff0c;它应当具备更多的功能和意义。只有这样&#xff0c;它的发展才能够真正全面和完善。产业互联网的衍生和出现&#xff0c;正是在互联网进化的基础之上出现的。这是我们看到之所以会有那么多的互联网玩家投身到产业互联网的浪…

FITC-PEG-FA,荧光素-聚乙二醇-叶酸,FA-PEG-FITC,实验室科研试剂,提供质量检测

FITC-PEG-FA&#xff0c;荧光素-聚乙二醇-叶酸 中文名称&#xff1a;荧光素-聚乙二醇-叶酸 英文名称&#xff1a;FITC-PEG-FA 英文别名&#xff1a;Fluorescein-PEG-Folic Acid 性状&#xff1a;基于不同的分子量&#xff0c;呈白色/类白色固体&#xff0c;或粘稠液体。 溶…

第九节 使用设备树实现RGB 灯驱动

通过上一小节的学习&#xff0c;我们已经能够编写简单的设备树节点&#xff0c;并且使用常用的of 函数从设备树中获取我们想要的节点资源。这一小节我们带领大家使用设备树编写一个简单的RGB 灯驱动程序&#xff0c;加深对设备树的理解。 实验说明 本节实验使用到STM32MP1 开…

使用gitlab ci/cd来发布一个.net 项目

gitlab runner的安装和基本使用:https://bear-coding.blog.csdn.net/article/details/120591711安装并给项目配置完gitlab runner后再操作后面步骤。实现目标&#xff1a;master分支代码有变更的时候自动构建build。当开发人员在gitlab上给项目打一个tag标签分支的时候自动触发…

4.5.4 LinkedList

文章目录1.特点2.常用方法3.练习:LinkedList测试1.特点 链表,两端效率高,底层就是链表实现的 List接口的实现类&#xff0c;底层的数据结构为链表&#xff0c;内存空间是不连续的 元素有下标&#xff0c;有序允许存放重复的元素在数据量较大的情况下&#xff0c;查询慢&am…

代码随想录NO39 |0-1背包问题理论基础 416.分割等和子集

0-1背包问题理论基础 分割等和子集1. 0-1背包问题理论基础(二维数组实现)2. 0-1背包问题理论基础 二&#xff08;一维数组实现&#xff09;1. 0-1背包问题理论基础(二维数组实现) 背包问题一般分为这几种&#xff1a; 0-1背包问题&#xff1a;有n件物品和一个最多能背重量为w…

51单片机15单片机 时钟芯片DS1302【更新中】

前言 现在流行的串行时钟电路很多&#xff0c;如DS1302、 DS1307、PCF8485等。这些电路的接口简单、价格低廉、使用方便&#xff0c;被广泛地采用。 本文介绍的实时时钟电路DS1302是DALLAS公司的一种具有涓细电流充电能力的电路主要特点是采用串行数据传输&#xff0c;可为掉电…

配置与管理FTP服务器

FTP的概念及作用 FTP( 文件传输协议 ) 是目前Internet上流行的数据传输方法之一。利用FTP协议&#xff0c;可以在FTP服务器和客户机之间进行双向传输&#xff0c;既可以把数据从FTP服务器上下载到本地客户机&#xff0c;又可以从客户机上传数据到远程FTP服务器。FTP最初与WWW服…

[ECCV 2020] FGVC via progressive multi-granularity training of jigsaw patches

Contents IntroductionProgressive Multi-Granularity (PMG) training frameworkExperimentsReferencesIntroduction 不同于显式地寻找特征显著区域并抽取其特征,作者充分利用了 CNN 不同 stage 输出的特征图的语义粒度信息,并使用 Jigsaw Puzzle Generator 进行数据增强来帮…

MediaPipe之人体关键点检测>>>BlazePose论文精度

BlazePose: On-device Real-time Body Pose tracking BlazePose&#xff1a;设备上实时人体姿态跟踪 论文地址&#xff1a;[2006.10204] BlazePose: On-device Real-time Body Pose tracking (arxiv.org) 主要贡献: &#xff08;1&#xff09;提出一个新颖的身体姿态跟踪解决…

文件操作 -- IO

文章目录文件操作 -- IO文件 :文件路径 :文件的类型java 中的文件操作文件内容的相关操作字节流的读和写操作字符流的读和写操作代码案例代码案例一 &#xff1a;代码案例二 &#xff1a;代码案例三 &#xff1a;文件操作 – IO 文件 : 文件相比大家都不陌生把 &#xff0c; 打…

10 卷积神经网络CNN(基础篇)

文章目录全连接CNN过程卷积过程下采样过程全连接层卷积原理单通道卷积多通道卷积改进多通道总结以及课程代码卷积改进PaddingStride下采样过程大池化层&#xff08;Max Pooling&#xff09;简单卷积神经网络的实现课程代码本篇课程来源&#xff1a; 链接部分文本来源参考&#…

LSTM已死,Transformer当立(LSTM is dead. Long Live Transformers! ):上

回想一下在Seq2seq模型中,如何使用Attention。这里简要回顾一下【1】介绍的方法2(并以此为基础展开对Transformer的讨论)。 下图中包含一个encoder(左)和一个decoder(右)。对于decoder来说,给定一个输入,得到输出,如何进一步得到context vector 呢? 我们需要根据和…

网络工程师一定要学会的知识点:OSPF,今天给大家详细介绍

1. OSPF 概念OSPF&#xff08;Open Shortest Path First 开放式最短路径优先&#xff09;是一种动态路由协议&#xff0c;属于内部网关协议(Interior Gateway Protocol,简称 IGP)&#xff0c;是基于链路状态算法的路由协议。2. OSPF 的运行原理&#xff08;1&#xff09;OSPF 的…

后端开发必懂nginx面试40问

什么是Nginx&#xff1f; Nginx是一个 轻量级/高性能的反向代理Web服务器&#xff0c;用于 HTTP、HTTPS、SMTP、POP3 和 IMAP 协议。他实现非常高效的反向代理、负载平衡&#xff0c;他可以处理2-3万并发连接数&#xff0c;官方监测能支持5万并发&#xff0c;现在中国使用ngin…