Maven学习笔记总结

一、认识Maven

Maven是一款基于Java平台的项目管理和整合工具,它将项目的开发和管理过程抽象成一个项目对象模型(POM)。它可以帮助我们自动完成项目的编译、测试、打包、发布以及部署等工作。

它能够帮助开发者完成以下任务:
1.构建项目
2.管理依赖

Maven的核心理念:约定优于配置。Maven对项目的目录结构、测试用例命名方式等内容做了规定,凡是使用Maven管理的项目都必须准守这些规则。

Maven构建的默认项目结构

文件目录
Java源代码src/main/java
资源文件src/main/resources
测试源代码src/test/java
测试资源文件src/test/resources
打包输出文件target
编译输出文件target/classes

二、Maven的安装与配置

Maven是一个基于Java的项目管理工具,因此最基本的要求是在计算机上安装JDK。Maven的安装教程有很多,这里不做累述,可自行百度。

三、Maven基本组件POM.xml

POM文件中定义了项目的基本信息,用于描述项目如何构建、声明项目依赖等等。
在POM中我们可以配置项目所需依赖,插件,目标等等。

POM文件中的关键元素

元素描述
groupId项目组ID,定义当前项目隶属的组织或公司,一般使公司或组织的网址或URL的反写
artifactId项目ID,通常是项目的名称。
version项目版本

groupId和artifactId一起定义了项目在仓库中的位置。

Super POM
所有的POM均继承自一个父POM(Super POM),它包含了一些可以被继承的默认设置。

四、Maven依赖

Maven中的任何一个依赖、插件或者项目构建的输出,供其他项目引用。我们把这些称为构件也称依赖。为了方便用户使用,每个构件都可以使用Maven坐标作为其为标识,Maven 坐标包括 groupId、artifactId、version、packaging 等元素,只要用户提供了正确的坐标元素,Maven 就能找到对应的构件。

绝大多数的依赖都可以在 https://mvnrepository.com/中获取。

五、Maven仓库

Maven仓库分为两类:本地仓库和远程仓库。
Maven查找构件时,会首先查看本地仓库,找到直接引用此构件。若本地仓库没有,则会在远程仓库中查找,找到后下载到本地仓库使用。

远程仓库可以分为3个小类:中央仓库、私服、其他公共仓库。
中央仓库
由Maven社区提供的一种特殊的远程仓库,它包含了绝大多数流行的开源构件。是默认查找的远程仓库。
私服
设立在局域网中的一种特殊的远程仓库,它用于代理所有外部的远程仓库。使用它恶意节省带宽,且比外部的远程仓库更加稳定。

六、Maven的生命周期

Maven的整个生命周期将项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有构建过程都进行了抽象与统一。Maven的生命周期是抽象的,它的实际工作都要通过插件中的插件目标(plugin goal)来完成。

Maven拥有的三套生命周期
clean:用于清理项目。
default:用于构建项目。
site:用于建立项目站点。

七、Maven项目的打包及如何引入本地依赖

使用mvn clean package可以将本地项目打包成一个jar文件,使用以下方式将打包的本地依赖在项目中引用。

<!--外部依赖-->
<dependency>
    <groupId>net.biancheng.www</groupId>
    <artifactId>helloMaven</artifactId>
     <!--依赖范围-->
    <scope>system</scope>
    <version>1.0-SNAPSHOT</version>
    <!--依赖所在位置-->
    <systemPath>D:\maven\helloMaven\target\helloMaven-1.0-SNAPSHOT.jar</systemPath>
</dependency>

在以上配置中,除了依赖的坐标信息外,外部依赖还使用了 scope 和 systemPath 两个元素。
scope 表示依赖范围,这里取值必须是 system,即系统。
systemPath 表示依赖的本地构件的位置。

八、Maven站点

用户可以使用 Maven 提供的 maven-site-plugin 插件让 Maven 生成一个 Web 站点, 以站点的形式发布项目描述、SCM 地址、许可证信息,开发者信息等信息。

添加项目依赖

<build>
    <plugins>
        <!--添加site 插件-->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-site-plugin</artifactId>
            <version>3.7.1</version>
        </plugin>
    </plugins>
</build>

使用mvn site命令生成站定,执行完毕后,可以在项目的 target\site 目录下找到 Maven 生成的站点文件。

九、Maven Archetype

Archetype是Maven项目的模板工具包,它定义了Maven项目的基本架构。Archetype提供了数千种创建Maven项目的模板,用于快速生成项目的目录结构即POM文件。

Maven Archetype 由下面 5 个模块组成:
maven-archetype-plugin:Archetype 插件。
archetype-packaging:用于描述 Archetype 的生命周期与构建项目软件包。
archetype-models:用于描述类与引用。
archetype-common:核心类。
archetype-testing:用于测试 Maven Archetype 的内部组件。

十、Maven SNAPSHOT与RELEASE版本

SNAPSHOT版本
如果我们需要在短时间内高频率地更新代码以及发布版本,就可以使用SNAPSHOT(快照)版本,它表示当前开发进度的副本。与常规版本不同,快照版本的构件在发布时,Maven 会自动为它打上一个时间戳,有了这个时间戳后,当依赖该构件的项目进行构建时,Maven 就能从仓库中找到最新的 SNAPSHOT 版本文件。

定义一个组件或模块为快照版本,只需要在pom.xml中在本版号(version元素的值)后加上-SNAPSHOT,例:

<groupId>net.biancheng.www</groupId>
<artifactId>helloMaven</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>

默认情况下对于快照本本的构件,Maven 会每天从仓库中获取一次更新,用户也可以在任何 Maven 命令中使用 -U 参数强制 Maven 检查更新。命令如下:

mvn clean package -U

RELEASE版本
RELEASE版本是不带-SHAPSHOT的版本。

区别SNAPSHOT版本RELEASE版本
定义版本中带-SNAPSHOT版本中不带-SNAPSHOT
发布仓库SNAPSHOT快照仓库RELEASE发行仓库
是否自动从远程仓库自动获取更新在不更改版本号的前提下,直接编译打包时,Maven 会自动从远程仓库上下载最新的快照版本。在不更改版本号的前提下,直接编译打包时,如果本地仓库已经存在该版本的模块,则 Maven 不会主动去远程仓库下载。
稳定性对应了大量带有时间戳的构件,具有不稳定性。只对应了唯一的构件,具有稳定性。
使用场景快照版本只应该在组织内部的项目中依赖使用。Maven 项目使用的组织外的依赖项都应该时发布版本的,不应该使用任何的快照版本依赖,否则会造成潜在的风险。
发布前是否需要修改当项目经过完善的测试后,需要上线时,应该将项目从快照版本更改为发布版本不需要修改

十、依赖传递

如果项目A依赖于项目B,项目B依赖于项目C。那么项目A就会将项目B所依赖的项目C也引到项目A中。这就是所谓的依赖传递。

通过依赖传递可能会出现依赖重复或依赖冲突的情况,针对这些情况可以使用以下功能进行处理。
1、依赖范围(Dependency scope)
编译时,Maven 会将与编译相关的依赖引入到编译 classpath 中;测试时,Maven 会将与测试相关的的依赖引入到测试 classpath 中;运行时,Maven 会将与运行相关的依赖引入到运行 classpath 中。这就是依赖范围。我们可以在POM的依赖声明中使用scope元素来指定依赖范围。
Maven中具有6种常见的依赖范围:

依赖范围描述
compilescope的缺省值。使用此依赖范围,上述三种classpath均被引入。如log4j在编译、测试、运行过程中都是必须的
test只对测试classpath有效
  • 依赖调解(Dependency mediation)
  • 可选依赖(Optional dependencies)
  • 排除依赖(Excluded dependencies)
  • 依赖管理(Dependency management)

十一、Maven POM元素继承

当一个项目包含多个模块时,可以在该项目中再创建一个父模块,并在其 POM 中声明依赖,其他模块的 POM 可通过继承父模块的 POM 来获得对父类的相关元素包括依赖的声明。注意此时的父项目POM的打包方式必须是pom。
实现方式:
父项目

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.biancheng.www</groupId>
    <artifactId>Root</artifactId>
    <version>1.0</version>
    <!--定义的父类 POM 打包类型使pom  -->
    <packaging>pom</packaging>
   
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.18</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
</project>

子项目继承父项目的POM

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.biancheng.www</groupId>
    <artifactId>App-Core-lib</artifactId>
    <version>1.0</version>
    <parent>
        <groupId>net.biancheng.www</groupId>
        <artifactId>Root</artifactId>
        <version>1.0</version>
        <relativePath>../Root</relativePath>
    </parent>
    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
</project>

子项目可以从父项目继承的POM元素有:

元素描述
groupId项目组 ID,项目坐标的核心元素
version项目版本,项目坐标的核心元素
description项目的描述信息
organization项目的组织信息
inceptionYear项目的创始年份
url项目的URL地址
developers项目的开发者信息
contributors项目的贡献者信息
distributionManagement项目的部署配置
issueManagement项目的缺陷跟踪系统信息
ciManagement项目的持续集成系统信息
scm项目的版本控制系统信息
mailingLists项目的邮件列表信息
properties自定义的Maven属性
dependencies项目的依赖配置
dependencyManagement项目的依赖管理配置
repositories项目的仓库配置
build包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等
reporting包括项目的报告输出目录配置、报告插件配置等

可选依赖
假设存在这样的依赖关系,A 依赖于 B,B 依赖于 X,B 又依赖于 Y。B 实现了两个特性,其中一个特性依赖于 X,另一个特性依赖于 Y,且两个特性是互斥的关系,用户无法同时使用两个特性,所以 A 需要排除 X,此时就可以在 B 中将 X 设置为可选依赖。
在 B 的 POM 关于 X 的依赖声明中使用 optional 元素,将其设置成可选依赖,示例配置如下。

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.biancheng.www</groupId>
    <artifactId>B</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>net.biancheng.www</groupId>
            <artifactId>X</artifactId>
            <version>1.0-SNAPSHOT</version>
            <!--设置可选依赖  -->
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

关于 optional 元素及可选依赖说明如下:
可选依赖用来控制当前依赖是否向下传递成为间接依赖;
optional 默认值为 false,表示可以向下传递称为间接依赖;
若 optional 元素取值为 true,则表示当前依赖不能向下传递成为间接依赖。

排除依赖
与上文的应用场景相同,也是 A 希望排除间接依赖 X,除了在 B 中设置可选依赖外,我们还可以在 A 中将间接依赖 X 排除。排除依赖是通过在 A 项目中使用 exclusions 元素实现,该元素下可以包含若干个 exclusion 子元素,用于排除若干个间接依赖,示例代码如下。

<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>net.biancheng.www</groupId>
    <artifactId>A</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>net.biancheng.www</groupId>
            <artifactId>B</artifactId>
            <version>1.0-SNAPSHOT</version>
            <exclusions>
                <!-- 设置排除 -->
                <!-- 排除依赖必须基于直接依赖中的间接依赖设置为可以依赖为 false -->
                <!-- 设置当前依赖中是否使用间接依赖 -->
                <exclusion>
                    <!--设置具体排除-->
                    <groupId>net.biancheng.www</groupId>
                    <artifactId>X</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</project>

关于 exclusions 元素及排除依赖说明如下:
排除依赖是控制当前项目是否使用其直接依赖传递下来的接间依赖;
exclusions 元素下可以包含若干个 exclusion 子元素,用于排除若干个间接依赖;
exclusion 元素用来设置具体排除的间接依赖,该元素包含两个子元素:groupId 和 artifactId,用来确定需要排除的间接依赖的坐标信息;
exclusion 元素中只需要设置 groupId 和 artifactId 就可以确定需要排除的依赖,无需指定版本 version。

十二、dependencyManagement

Maven 可以通过 dependencyManagement 元素对依赖进行管理,它具有以下 2 大特性:
在该元素下声明的依赖不会实际引入到模块中,只有在 dependencies 元素下同样声明了该依赖,才会引入到模块中。
该元素能够约束 dependencies 下依赖的使用,即 dependencies 声明的依赖若未指定版本,则使用 dependencyManagement 中指定的版本,否则将覆盖 dependencyManagement 中的版本。
例:

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!--由于不是继承,所以必须重新添加 groupId 和 version-->
    <groupId>net.biancheng.www</groupId>
    <artifactId>App-Data-lib</artifactId>
    <version>1.0</version>
    <!--dependencyManagement 标签用于控制子模块的依赖版本等信息 -->
    <!-- 该标签只用来控制版本,不能将依赖引入 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <!--引用的properties标签中定义的属性 -->
                <version>1.2.17</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <!--引用的properties标签中定义的属性 -->
                <version>4.9</version>
                <!-- <scope>test</scope> -->
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <!--引用的properties标签中定义的属性 -->
                <version>5.1.18</version>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>c3p0</groupId>
                <artifactId>c3p0</artifactId>
                <!--引用的properties标签中定义的属性 -->
                <version>0.9.1</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <!--声明依赖-->
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>
</project>

子项目只需要直接引入父项目中声明的依赖即可。

导入依赖管理
使用import关键字可以将目标 pom.xml 中的 dependencyManagement 配置导入合并到当前 pom.xml 的 dependencyManagement 中。
例:

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!--由于不是继承,所以必须重新添加 groupId 和 version-->
    <groupId>net.biancheng.www</groupId>
    <artifactId>App-Data-lib</artifactId>
    <version>1.0</version>
    <!--定义依赖管理-->
    <dependencyManagement>
        <dependencies>
            <!--导入依赖管理配置-->
            <dependency>
                <groupId>net.biancheng.www</groupId>
                <artifactId>Root</artifactId>
                <version>1.0</version>
                <!--依赖范围为 import-->
                <scope>import</scope>
                <!--类型一般为pom-->
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <!--声明依赖-->
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>
</project>

十三、Maven聚合

Maven的聚合功能用于模块的整合,与父模块相似,聚合模块的打包方式(packaging)也是 pom,用户可以在其 POM 中通过 modules 下的 module 子元素来添加需要聚合的模块的目录路径。

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.biancheng.www</groupId>
    <artifactId>Root</artifactId>
    <version>1.0</version>
    <!--定义的父类pom.xml 打包类型使pom -->
    <packaging>pom</packaging>
    <properties>
        <!-- 定义一些属性 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <log4j.version>1.2.17</log4j.version>
        <junit.version>4.9</junit.version>
        <system.version>1.0</system.version>
        <mysql.connector.version>5.1.18</mysql.connector.version>
        <c3p0.version>0.9.1</c3p0.version>
    </properties>
    <!--dependencyManagement 标签用于控制子模块的依赖版本等信息 -->
    <!-- 该标签只用来控制版本,不能将依赖引入 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <!--引用的properties标签中定义的属性 -->
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <!--引用的properties标签中定义的属性 -->
                <version>${junit.version}</version>
                <!-- <scope>test</scope> -->
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <!--引用的properties标签中定义的属性 -->
                <version>${mysql.connector.version}</version>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>c3p0</groupId>
                <artifactId>c3p0</artifactId>
                <!--引用的properties标签中定义的属性 -->
                <version>${c3p0.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <!--添加需要聚合的模块-->
    <modules>
        <module>../App-Core-lib</module>
        <module>../App-Data-lib</module>
        <module>../App-UI-WAR</module>
    </modules>
</project>

继承与聚合的关系
Maven 的继承和聚合的目的不同,继承的目的是为了消除 POM 中的重复配置,聚合的目的是为了方便快速的构建项目。
对于继承中的父模块来说,它跟本不知道那些模块继承了它,但子模块都知道自己的父模块是谁。
对于聚合模块来说,它知道哪些模块被聚合了,但那些被聚合的模块根本不知道聚合模块的存在。
两者在结构和形式上还是有一定的共同点的,最直观的就是两者的打包方式都是 pom,两者除了 POM 外都没有实际的代码内容。

十四、Maven镜像

如果一个仓库 A 可以提供另一个仓库 B 的所有内容,那么就可以认为仓库 A 是仓库 B 的一个镜像。
使用镜像代替中央仓库
国内开发人员由于网络原因,直接从中央仓库下载构件时,速度较慢或不稳定,我们通常会使用中央仓库的国内镜像站来解决该问题。
配置 Maven 镜像的方法也非常的简单,我们只需要在 Maven 安装目录中 setting.xml 文件的 mirrors 节点中,使用 mirror 标签添加镜像的相关信息即可。
镜像是用于加速资源的下载。在apache-maven-3.6.3\conf下的settings.xml文件配置。

阿里云镜像地址

<mirror>
    <id>aliyun</id>
    <mirrorOf>central</mirrorOf>
    <name>aliyun</name>
    <url>https://maven.aliyun.com/repository/public</url>
</mirror>

华为云镜像地址

<mirror>
    <id>huaweicloud</id>
    <name>mirror from maven huaweicloud</name>
    <mirrorOf>central</mirrorOf>
    <url>https://repo.huaweicloud.com/repository/maven/</url>
</mirror>

十五、Maven私服

Maven私服是一种特殊的远程仓库,它架设在局域网上,用于代理外部的远程仓库。
建立私服后,用户下载使用依赖的顺序就变成了 本地仓库——Maven私服——远程仓库。
使用Maven私服的好处
1、节省外网带宽。大量对于外部远程仓库的重复请求,会消耗很大量的带宽,利用 Maven 私服代理外部仓库后,能够消除对外部仓库的大量重复请求,降低外网带宽压力。
2、位于局域网之中,下载构建更快更稳定。
3、提高项目的稳定性,增强对项目的控制。如果不建立私服,那么 Maven 项目的构件就高度依赖外部的远程仓库,若外部网络不稳定,则项目的构建过程也会变得不稳定。
建立私服后,即使外部网络状况不佳甚至中断,只要私服中已经缓存了所需的构件,Maven 也能够正常运行。一些私服软件(如 Nexus)提供了很多额外控制功能,例如,权限管理、RELEASE/SNAPSHOT 版本控制等,可以对仓库进行一些更加高级的控制。
4、降低中央仓库得负荷压力。

十六、资源文件导出设置

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
        <includes>
            <include>**/*.properties</include>
            <include>**/*.xml</include>
        </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值