Maven的基础知识详细解析

1 简介

Maven是Apache软件基金会唯一维护的一款自动化构建工具,专注于服务Java平台的项目构建依赖管理

Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

在有多个开发团队环境的情况下,Maven 能够在很短的时间内使得每项工作都按照标准进行。因为大部分的工程配置操作都非常简单并且可复用,在创建报告、检查、构建和测试自动配置时,Maven 可以让开发者的工作变得更简单。

2 完成工作

  • 构建项目(打包,编译等)
  • 文档生成
  • 报告
  • 依赖(jar包之间的依赖关系)
  • SCMs
  • 发布
  • 分发
  • 添加第三方jar包
  • 邮件列表

3 工作原理

4 常用命令

mvn -version/-v —— 显示版本信息
mvn clean —— 清空生成的文件
mvn compile  ——  编译
mvn test  ——  编译并测试
mvn package  ——  生成target目录,编译、测试代码,生成测试报告,生成jar/war文件
mvn site  ——  生成项目相关信息的网站
mvn clean compile  —— 表示先运行清理之后运行编译,会将代码编译到target文件夹中
mvn clean package  —— 运行清理和打包
mvn clean install ——  运行清理和安装,会将打好的包安装到本地仓库中,以便其他的项目可以调用
mvn clean deploy  —— 运行清理和发布

5 核心概念

概念说明
LifeCycle生命周期,maven内置default,sie,clean三个生命周期
Phase阶段,每个生命周期有不同的阶段
Plugin插件,实现实际的构建功能
Goal一个插件可以实现多个goal,goal具备具体的功能
Execution通过配置,决定在某个Phase执行哪些Goal
Projectmaven管理的目标:软件工程,小的工程可以聚合成大工程
PackageType为了便于管理工程,按照构建目标区分成不同的工程类型,如jar,war,ear等
Dependency依赖,project之间存在依赖关系
DependencyScopemaven对依赖定义了不同的作用范围
Management可以配置一个工程如何管理依赖关系
Repository仓库,存放包,分为本地库和远程库
Build构建的动作。使用maven管理工程,主要是指定将project构建到某个phase

6 几种常见核心概念介绍

6.1 Maven约定的工程目录

Java开发领域普遍认同的一个观点:约定>配置>编码(能用配置解决的问题就不编码,能基于约定的就不配置)

6.2 POM

Maven项目的核心是pom.xml。POM(Project Object Model,项目对象模型)定义了项目的基本信息,用于描述项目如何构建,声明项目依赖等。

  • modelVersion:指定当前POM模型的版本,对Maven2和Maven3来说,他只能是4.0.0
  • groupId:项目的所属公司或组织的域名倒写
  • artifactId:如果该项目为一个Maven模块,则相当于项目名;如果一个项目包含多个子模块,则它们该模块的名称;(一般和项目同名)
  • version:该项目的版本信息
  • name:项目名,作用只是一个更友好的项目名称,不是必须的。
  • packaging:打包方式,默认为jar

6.3 依赖管理

Maven 一个核心的特性就是依赖管理。当我们处理多模块的项目(包含成百上千个模块或者子项目),模块间的依赖关系就变得非常复杂,管理也变得很困难。针对此种情形,Maven 提供了一种高度控制的方法。

① 如何引入 jar 包

在代码开发时,如果需要使用第三方 jar 包提供的类库,那么需要在 pom.xml 加入该 jar 包依赖。
例如:使用 zookeeper client

<dependencies>
  <!-- https://mvnrepository.com/artifact/org.apache.hadoop/zookeeper -->
  <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>zookeeper</artifactId>
      <version>3.3.1</version>
  </dependency>
</dependencies>

② Maven 如何解析 jar 包依赖——传递依赖

如上所述,在 pom.xml 中引入 zookeeper jar 包依赖,当 Maven 解析该依赖时,需要引入的 jar 包不仅仅只有 zookeeper,还会有 zookeeper 内部依赖的 jar 包,还会有 zookeeper 内部依赖的 jar 包依赖的 jar 包......,依赖关系不断传递,直至没有依赖。
例如:上述 pom.xml 引入 zookeeper 依赖,实际引入的 jar 包有:

③ 依赖的范围

有时依赖信息中除了目标 jar 包的坐标还有一个 scope 设置,这就是依赖的范围。依赖的范围有几个可选值,常用的有:compile、test、provided 三个,当然还有不常用的 runtime、system..

  • compile默认范围,编译测试运行都有效

  • provided:在编译和测试时有效

  • runtime:在测试和运行时有效

  • test:只在测试时有效

  • system:在编译和测试时有效,与本机系统关联,可移植性差

  • 常用依赖范围有效性总结

④ 包冲突如何产生?

举个🌰:假设 A->B->C->D1, E->F->D2,D1,D2 分别为 D 的不同版本。
如果 pom.xml 文件中引入了 A 和 E 之后,按照 Maven 传递依赖原则,工程内需要引入的实际 Jar 包将会有:A B C D1 和 E F D2,因此 D1,D2 将会产生包冲突。

⑤ 如何解决包冲突?

Maven 解析 pom.xml 文件时,同一个 jar 包只会保留一个,这样有效的避免因引入两个 jar 包导致的工程运行不稳定性。

Maven 默认处理策略

  • 最短路径优先
    Maven 面对 D1 和 D2 时,会默认选择最短路径的那个 jar 包,即 D2。E->F->D2 比 A->B->C->D1 路径短 1。
  • 最先声明优先
    如果路径一样的话,举个🌰: A->B->C1, E->F->C2 ,两个依赖路径长度都是 2,那么就选择最先声明。

⑥ 移除依赖

如果我们不想通过 A->B->->D1 引入 D1 的话,那么我们在声明引入 A 的时候将 D1 排除掉,这样也避免了包冲突。
举个🌰:将 zookeeper 的 jline 依赖排除

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.3.1</version>
    <exclusions>
        <exclusion>
            <groupId>jline</groupId>
            <artifactId>jline</artifactId>
        </exclusion>
    </exclusions>
</dependency>

⑦ 检测包冲突工具

mvn dependency:help
mvn dependency:analyze
mvn dependency:tree
mvn dependency:tree -Dverbose

6.4 Repository(存储库)

Maven Repository/存储库,顾名思义是一个存储JAR文件的仓库,Maven根据项目中pom.xml文件中提供的jar包依赖信息,从存储库中查找并获取需要的jar包。

① 分类

  • Local Repository – 本地库:Maven本地存储库是本机中的一个目录。如果目录不存在,执行maven时就会先创建它。
    默认情况下,maven本地存储库是 %USER_HOME%/.m2 目录,例如:C:\Users\Kevin\.m2
  • Central Repository – 中央库:Maven中央库主要放置公共jar包,是由apache maven社区创建的,中央库的网址是http://repo1.maven.org/maven2,可以通过网址http://search.maven.org/#browse查看有哪些公共jar包。
  • Remote Repository – 远程库:Maven远程库也是位于网络上的存储库。例如一个公司可能有很多共享的jar包文件,就可以搭建一个公司内部的远程库,供众多开发人员使用;中央库可以认为是一个特殊的远程库。

Maven搜索依赖项时,会按照:本地库、中央库和远程库的顺序进行。

如果这些库中没找到依赖项,Maven将报错。

6.5 生命周期

Maven有3个内置的构建生命周期:
  • default – 编译源代码并处理打包项目相关的所有事情
  • clean – 清理构建输出,包括生成的编译类、JAR文件等
  • site – 为项目生成文档

 ① Default 生命周期

  • 清理(clean):删除以前的编译结果,为重新编译做好准备。
  • 验证(validate):验证项目是否正确,所有必需的信息是否可用。
  • 编译(compile):将Java 源程序编译为字节码文件。
  • 测试(test):针对项目中的关键点进行测试,确保项目在迭代开发过程中关键点的正确性。
  • 打包(package):将一个包含诸多文件的工程封装为一个压缩文件用于安装或部署。Java 工程对应 jar 包,Web工程对应 war 包。
  • 安装(install):在 Maven 环境下特指将打包的结果——jar 包或 war 包安装到本地仓库中。
  • 报告:在每一次测试后以标准的格式记录和展示测试结果。
  • 部署(deploy):将打包的结果部署到远程仓库或将 war 包部署到服务器上运行。

② Clean 生命周期

Clean 生命周期一共包含了三个阶段:

  • pre-clean 执行一些需要在 clean 之前完成的工作
  • clean 移除所有上一次构建生成的文件
  • post-clean 执行一些需要在 clean 之后立刻完成的工作

③ Site 生命周期

  • pre-site 执行一些需要在生成站点文档之前完成的工作
  • site 生成项目的站点文档
  • post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
  • site-deploy 将生成的站点文档部署到特定的服务器上 这里经常用到的是 site 阶段和 site-deploy 阶段,用以生成和发布 Maven 站点,这可是 Maven 相当强大 的功能,Manager 比较喜欢,文档及统计数据自动生成,很好看。

6.6 插件和目标

 Maven实际上是一个插件执行框架,Maven中的所有任务都是由插件完成的。

Maven插件是构建目标的集合,也称为MOJO (Maven Old Java Object)。可以把插件理解为一个类,而构建目标是类中的方法。构建阶段包含一系列的构建目标,可以理解为按顺序调用各个插件中的构建目标(方法),然后一系列的构建阶段组成一个构建生命周期。

构建目标可以绑定到多个构建阶段,也可以不绑定,就像类的方法可以被调用,也可以不被调用。

<build>
    <plugins>
        <plugin>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>${maven.failsafe.version}</version>
            <executions>
                <execution>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

这是一个故障安全插件的简单配置,负责运行集成测试。可以看到,插件有两个主要目标:

  • integration-test: 运行集成测试
  • verify: 验证所有通过的集成测试

插件类型

Maven提供了2种类型的插件:

  • 构建类插件 – 在构建过程中执行,pom中<build/>元素中配置。
  • 报告类插件 – 在文档生成过程中执行,pom中<reporting/>元素中配置。

下面是一些maven内置的常用插件:

  • clean
  • compiler
  • surefire
  • jar
  • war
  • javadoc
  • antrun

自定义插件

如果maven内置插件不能满足项目需求,也可以开发自定义插件。

开发自定义插件可参考官网

6.7 继承

  • 为什么需要继承机制? 由于非 compile 范围的依赖信息是不能在“依赖链”中传递的,所以有需要的工程只能单独配置
  • 创建父工程 创建父工程和创建一般的 Java 工程操作一致,唯一需要注意的是:打包方式处要设置为 pom
  • 在子工程中引用父工程 ,从当前目录到父项目的 pom.xml 文件的相对路径
 <parent>
 	<groupId>com.starfish.maven</groupId>
	<artifactId>Parent</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<!-- 以当前文件为基准的父工程pom.xml文件的相对路径 -->
	<relativePath>../Parent/pom.xml</relativePath>
</parent>

此时如果子工程的 groupId 和 version 如果和父工程重复则可以删除。

  • 在父工程中管理依赖 将 Parent 项目中的 dependencies 标签,用 dependencyManagement 标签括起来
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</dependencyManagement> 
复制代码

在子项目中重新指定需要的依赖,删除范围和版本号

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
</dependency>

6.8 聚合

  • 为什么要使用聚合?

将多个工程拆分为模块后,需要手动逐个安装到仓库后依赖才能够生效。修改源码后也需要逐个手动进 行 clean 操作。而使用了聚合之后就可以批量进行 Maven 工程的安装、清理工作。

如何配置聚合? 在总的聚合工程中使用 modules/module 标签组合,指定模块工程的相对路径即可

<!-- 配置聚合 -->
<modules>
    <!-- 指定各个子工程的相对路径 -->
    <module>starfish-learn-grpc</module>
    <module>starfish-learn-kafka</module>
    <module>starfish-web-demo</module>
</modules>

6.9 profile

profile让你能够在特定场景下使用与基本配置不同的配置构建项目。你不需要创建多个单独的POM文件,只需在单个POM文件中包含不同的profile配置,这些profile配置在特定场景下将覆盖pom中的基本配置。

例如,项目中需要构建开发版本、测试版本以及正式版本,这些版本可以通过在pom文件中添加不同构建profile构建。执行maven时指定不同的构建profile就可以。

<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.qikegu.demo</groupId>
  <artifactId>mybatis-demo</artifactId>
  <version>1.0.0</version>

  <profiles>
      <profile>
          <id>test</id>
          <activation>...</activation>
          <build>...</build>
          <modules>...</modules>
          <repositories>...</repositories>
          <pluginRepositories>...</pluginRepositories>
          <dependencies>...</dependencies>
          <reporting>...</reporting>
          <dependencyManagement>...</dependencyManagement>
          <distributionManagement>...</distributionManagement>
      </profile>
  </profiles>

</project>
  • profile中的元素将覆盖POM中同名元素的值。
  • <activation>设置触发profile生效的条件
  • 也可在maven命令行中指定profile:-P profile-name

  

参考

https://www.cnblogs.com/shengs/p/5517220.html

https://juejin.im/post/5e215a9ee51d453c951daa64

https://www.jianshu.com/p/f6ca45865025

https://www.qikegu.com/docs/2471

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Halo 咯咯

有你的支持我会更加努力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值