Maven学习记录

一、简介

1. Maven:

基于 Java 平台的项目管理和整合工具,将项目的开发和管理过程抽象成一个项目对象模型(POM)。开发人员只需要做一些简单的配置,Maven 就可以自动完成项目的编译、测试、打包、发布以及部署等工作。具有跨平台性

2. 特点

  1. 设置简单。
  2. 所有项目的用法一致。
  3. 可以管理和自动进行更新依赖。
  4. 庞大且不断增长的资源库。
  5. 可扩展,使用 Java 或脚本语言可以轻松的编写插件。
  6. 几乎无需额外配置,即可立即访问新功能。
  7. 基于模型的构建:Maven 能够将任意数量的项目构建为预定义的输出类型,例如 JAR,WAR。
  8. 项目信息采取集中式的元数据管理:使用与构建过程相同的元数据,Maven 能够生成一个网站(site)和一个包含完整文档的 PDF。
  9. 发布管理和发行发布:Maven 可以与源代码控制系统(例如 Git、SVN)集成并管理项目的发布。
  10. 向后兼容性:您可以轻松地将项目从旧版本的 Maven 移植到更高版本的 Maven 中。
  11. 并行构建:它能够分析项目依赖关系,并行构建工作,使用此功能,可以将性能提高 20%-50%。
  12. 更好的错误和完整性报告:Maven 使用了较为完善的错误报告机制,它提供了指向 Maven Wiki 页面的链接,您将在其中获得有关错误的完整描述。

 3.默认项目结构

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

二、POM 

1. POM(Project Object Model,项目对象模型)是 Maven 的基本组件,它是以 xml 文件的形式存放在项目的根目录下,名称为 pom.xml。
2. POM 中定义了项目的基本信息,用于描述项目如何构建、声明项目依赖等等。
3. 当 Maven 执行一个任务时,它会先查找当前项目的 POM 文件,读取所需的配置信息,然后执行任务。在 POM 中可以设置如下配置:
  • 项目依赖
  • 插件
  • 目标
  • 构建时的配置文件
  • 版本 
  • 开发者
  • 邮件列表

4. pom.xml示例

<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>maven</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</project>
  1. 在创建 POM 之前,首先要确定工程组(groupId),及其名称(artifactId)和版本,在仓库中这些属性是项目的唯一标识。
  2. 所有的 Maven 项目都有一个 POM 文件,所有的 POM 文件都必须有 project 元素和 3 个必填字段:groupId、artifactId 以及 version。

节点 描述
groupId 项目组 ID,定义当前 Maven 项目隶属的组织或公司,通常是唯一的。它的取值一般是项目所属公司或组织的网址或 URL 的反写,例如 net.biancheng.www。
artifactId 项目 ID,通常是项目的名称。groupId 和 artifactId 一起定义了项目在仓库中的位置。
version 项目版本。
       3. 所有的 POM 均继承自一个父 POM,这个父 POM 被称为 Super POM,它包含了一些可以被继承的默认设置。

5. Maven坐标

  1. 为什么引入坐标:在 Maven 中,任何一个依赖、插件或者项目构建的输出,都可以称为构件。在 Maven 世界中存在着众多构件,在引入坐标概念之前,当用户需要使用某个构件时,只能去对应的网站寻找,使得用户将大量的时间浪费在搜索和寻找上,严重地影响了研发效率。为了解决这个问题,于是 Maven 引入了 Maven 坐标的概念。
  2. 规定:世界上任何一个构件都可以使用 Maven 坐标并作为其唯一标识,该坐标定义了构件在仓库中的唯一存储路径。Maven 坐标包括 groupId、artifactId、version、packaging 等元素,只要用户提供了正确的坐标元素,Maven 就能找到对应的构件。groupId、artifactId 和 version 是必须定义的,packaging 是可选的。
  • groupId: 项目组 ID,定义当前 Maven 项目隶属的组织或公司,通常是唯一的。它的取值一般是项目所属公司或组织的网址或 URL 的反写,例如 net.biancheng.www。
  • artifactId: 项目 ID,通常是项目的名称。
  • version:版本。
  • packaging:项目的打包方式,默认值为 jar
<project> 
    <groupId>net.biancheng.www</groupId>
    <artifactId>helloMaven</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
</project>

6. Maven依赖

  • 如果一个 Maven 构建所产生的构件(例如 Jar 文件)被其他项目引用,那么该构件就是其他项目的依赖。
  • Maven 坐标是依赖的前提,所有 Maven 项目必须明确定义自己的坐标
  • 当 Maven 项目需要声明某一个依赖时,通常只需要在其 POM 中配置该依赖的坐标信息,Maven 会根据坐标自动将依赖下载到项目中。
<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">
...
    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
dependencies 元素可以包含一个或者多个 dependency 子元素,用以声明一个或者多个项目依赖,每个依赖都可以包含以下元素:
  • groupId、artifactId 和 version:依赖的基本坐标,对于任何一个依赖来说,基本坐标是最重要的,Maven 根据坐标才能找到需要的依赖。
  • type:依赖的类型,对应于项目坐标定义的 packaging。大部分情况下,该元素不必声明,其默认值是 jar。
  • scope:依赖的范围。
  • optional:标记依赖是否可选。
  • exclusions:用来排除传递性依赖。
大部分依赖声明只包含 groupId、artifactId 和 version 三个元素,至于 scope、optional 以及 exclusions 等元素,了解即可
  • 获取依赖坐标:https://mvnrepository.com/  搜索、复制
  • 导入本地jar包:Maven导入本地jar包
        某一个项目需要依赖于存储在本地的某个 jar 包,该 jar 包无法从任何仓库中下载的,这种依赖被称为外部依赖或本地依赖。
        在pom.xml中添加<dependency>:
<!--外部依赖-->
        <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 表示依赖范围,这里取值必须是 system,即系统。
  • systemPath 表示依赖的本地构件的位置。

三、Maven仓库

  • 仓库:统一存放依赖和插件的地方。
  • 当 Maven 项目需要某些构件时,只要其 POM 文件中声明了这些构件的坐标,Maven 就会根据这些坐标找自动到仓库中找到并使用它们。
  • Maven 仓库可以分为 2 个大类:本地仓库和远程仓库(*仓库、私服、其他公共仓库
        当 Maven 根据坐标寻找构件时,它会首先查看本地仓库,若本地仓库存在此构件,则直接使用;
        若本地仓库不存在此构件,Maven 就会优先去远程仓库中的*仓库查找,再查找其他远程仓库(如果设置其他远程仓库),若发现所需的构件后,则下载到本地仓库使用;
        如果本地仓库和远程仓库都没有所需的构件,则 Maven 就会停止处理并抛出错误。
远程仓库还可以分为 3 个小类:*仓库、私服、其他公共仓库:
  • *仓库是由 Maven 社区提供的一种特殊的远程仓库,它包含了绝大多数流行的开源构件。在默认情况下,当本地仓库没有 Maven 所需的构件时,会首先尝试从*仓库下载。
  • 私服是一种特殊的远程仓库,它通常设立在局域网内,用来代理所有外部的远程仓库。它的好处是可以节省带宽,比外部的远程仓库更加稳定。 
  • 除了*仓库和私服外,还有很多其他公共仓库,例如 JBoss Maven 库,Java.net Maven 库等等。

1. 本地仓库:

  • 本地仓库实际上就是本地计算机上的一个目录(文件夹),它会在第一次执行 Maven 命令时被创建(当 Maven 项目第一次进行构建时,会自动从远程仓库搜索依赖项,并将其下载到本地仓库中)。
  • 构件只有储存在本地仓库中,才能被其他的 Maven 项目使用。构件想要进入本地仓库,除了从远程仓库下载到本地仓库外,还可以使用命令 mvn install 将本地项目的输出构件安装到本地仓库中。

2. *仓库:

  • 包含绝大多数流行的开源构件,由 Maven 社区管理,不需要配置,需要通过网络才能访问
http://search.maven.org/#browse

3. 远程仓库:

  • 由开发人员自己定制的仓库

4. 私服:

  • 特殊的远程仓库,它是架设在局域网内的仓库服务,用来代理位于外部的远程仓库(*仓库、其他远程公共仓库)。
  • 建立私服后,Maven 依赖搜索顺序:本地仓库——>私服(下载到本地仓库)——>外部的远程仓库(下载并缓存到 Maven 私服)——>报错。
  • 一些无法从外部仓库下载到的构件,也能从本地上传到私服供其他人使用。

  • 私服的优势:节省外网带宽、下载速度更快、便于部署第三方构件、提高项目的稳定性,增强对项目的控制、降低*仓库得负荷压力。
  • 私服的搭建:使用Maven仓库管理器(Apache Archiva、JFrog Artifactory、Sonatype Nexus)。

四、Maven生命周期

1. 使用Maven构建项目就是执行lifecycle,执行到指定的phase为止。每个phase会执行自己默认的一个或多个goal。goal是最小任务单元。
2. Maven的生命周期由一系列阶段(phase)构成,Maven 拥有三套标准的生命周期,三套生命周期本身是相互独立:
  • default:用于构建项目
  • clean:用于清理项目
  • site:用于建立项目站点
2.1 内置的生命周期default包含以下phase:
阶段 描述
validate 验证项目是否正确以及所有必要信息是否可用。
initialize 初始化构建状态。
generate-sources 生成编译阶段需要的所有源码文件。
process-sources 处理源码文件,例如过滤某些值。
generate-resources 生成项目打包阶段需要的资源文件。
process-resources 处理资源文件,并复制到输出目录,为打包阶段做准备。
compile 编译源代码,并移动到输出目录。
process-classes 处理编译生成的字节码文件
generate-test-sources 生成编译阶段需要的测试源代码。
process-test-sources 处理测试资源,并复制到测试输出目录。
test-compile 编译测试源代码并移动到测试输出目录中。
test 使用适当的单元测试框架(例如 JUnit)运行测试。
prepare-package 在真正打包之前,执行一些必要的操作。
package 获取编译后的代码,并按照可发布的格式进行打包,例如 JAR、WAR 或者 EAR 文件。
pre-integration-test 在集成测试执行之前,执行所需的操作,例如设置环境变量。
integration-test 处理和部署所需的包到集成测试能够运行的环境中。
post-integration-test 在集成测试被执行后执行必要的操作,例如清理环境。
verify 对集成测试的结果进行检查,以保证质量达标。
install 安装打包的项目到本地仓库,以供其他项目使用。
deploy 拷贝最终的包文件到远程仓库中,以共享给其他开发人员和项目。
如果我们运行mvn package,Maven就会执行default生命周期,它会从开始一直运行到package这个phase为止
2.2 Maven另一个常用的生命周期是clean,它会执行3个phase:
  • pre-clean  清理前
  • clean         清理(注意这个clean不是lifecycle而是phase)
  • post-clean  清理后
更复杂的例子是指定多个phase,例如,运行mvn clean package,Maven先执行clean生命周期并运行到clean这个phase,然后执行default生命周期并运行到package这个phase。 
2.3 site生命周期:目的是建立和部署项目站点,Maven 能够根据 POM 包含的信息,自动生成一个友好的站点,该站点包含一些与该项目相关的文档。
  • pre-site
  • site
  • post-site
  • site-deploy
 Maven站点(未看):Maven site(站点)
经常用到的phase其实只有几个:
  • clean:清理
  • compile:编译
  • test:运行测试
  • package:打包
3.  执行一个phase又会触发一个或多个goal,goal的命名总是abc:xyz这种形式
类比一下:
  • lifecycle相当于Java的package,它包含一个或多个phase;
  • phase相当于Java的class,它包含一个或多个goal;
  • goal相当于class的method,它其实才是真正干活的。

五、Maven插件

1. Maven 实际上是一个依赖插件执行的框架,它执行的每个任务实际上都由插件完成的。Maven 的核心发布包中并不包含任何 Maven 插件,它们以独立构件的形式存在, 只有在 Maven 需要使用某个插件时,才会去仓库中下载。
2. Maven 提供了如下 2 种类型的插件。
插件类型 描述
Build plugins 在项目构建过程中执行,在 pom.xml 中的 build 元素中配置 
Reporting plugins 在网站生成过程中执行,在 pom.xml 中的 reporting  元素中配置 
 3. 插件目标:plugin-goal
        为了提高代码的复用性,通常一个 Maven 插件能够实现多个功能,每一个功能都是一个插件目标,即 Maven 插件是插件目标的集合。我们可以把插件理解为一个类,而插件目标是类中的方法,调用插件目标就能实现对应的功能。
插件目标的通用写法:
[插件名]:[插件目标名]

例如,maven-compiler-plugin 插件的 compile 目标的通用写法为:
maven-compiler-plugin:compile

使用 Maven 命令执行插件的目标:
mvn [插件名]:[目标名]

例如,调用 maven-compiler-plugin 插件的 compile 目标
mvn compiler:compile
4. 插件绑定 
        为了完成某个具体的构建任务,Maven 生命周期的阶段需要和 Maven 插件的目标相互绑定。
        例如,代码编译任务对应了default 生命周期的 compile 阶段,而 maven-compiler-plugin 插件的 compile 目标能够完成这个任务,因此将它们进行绑定就能达到代码编译的目的。
        当插件目标绑定到生命周期的不同阶段时,其执行顺序由生命周期阶段的先后顺序决定。如果多个目标绑定到同一个生命周期阶段,其执行顺序与插件声明顺序一致,先声明的先执行,后声明的后执行。
  • 内置绑定:Maven 默认为一些核心的生命周期阶段绑定了插件目标,当用户调用这些阶段时,对应的插件目标就会自动执行相应的任务。
生命周期 阶段 插件目标 执行的任务
clean pre-clean
clean  maven-clean-plugin:clean 清理 Maven 的输出目录
post-clean
site pre-site
site maven-site-plugin:site 生成项目站点
post-site
site-deploy maven-site-plugin:deploy 部署项目站点
default process-resources   maven-resources-plugin:resources 复制资源文件到输出目录
compile maven-compiler-plugin:compile 编译代码到输出目录
process-test-resources   maven-resources-plugin:testResources 复制测试资源文件到测试输出目录
test-compile maven-compiler-plugin:testCompile 编译测试代码到测试输出目录
test maven-surefire-plugin:test 执行测试用例
package maven-jar-plugin:jar/maven-jar-plugin:war 创建项目 jar/war 包
install maven-install-plugin:install 将项目输出的包文件安装到本地仓库
deploy maven-deploy-plugin:deploy 将项目输出的包文件部署到到远程仓库
  • 自定义绑定:用户也可以自己选择将某个插件目标绑定到 Maven 生命周期的某个阶段上
<project>
...
    <build>
        <plugins>
            <!-- 绑定插件 maven-antrun-plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.8</version>
                <executions>
                    <execution>
                        <!--自定义 id -->
                        <id>www.biancheng.net clean</id>
                        <!--插件目标绑定的构建阶段 -->
                        <phase>clean</phase>
                        <!--插件目标 -->
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <!--配置 -->
                        <configuration>
                            <!-- 执行的任务 -->
                            <tasks>
                                <!--自定义文本信息 -->
                                <echo>清理阶段,编程帮 欢迎您的到来,网址:www.biancheng.net</echo>
                            </tasks>
                        </configuration>
                    </execution>               
                </executions>
            </plugin>
        </plugins>
    </build>
...
</project>
配置中除了插件的坐标信息之外,还通过 executions 元素定义了一些执行配置。executions 下的每一个 executin 子元素都可以用来配置执行一个任务。
execution 下各个元素含义如下:
  • id:任务的唯一标识。
  • phase:插件目标需要绑定的生命周期阶段。
  • goals:用于指定一组插件目标,其子元素 goal 用于指定一个插件目标。
  • configuration:该任务的配置,其子元素 tasks 用于指定该插件目标执行的任务。
5. 插件与依赖的区别
依赖:运行时开发时都需要,相当于写代码时候用到的包,需要通过这些包里的函数构建自己的代码,在打包时需要把这些依赖也打包进项目里;
插件:在项目开的发时需要,但是在项目运行时不需要,因此在项目开发完成后不需要把插件打包进项目中。插件是一种工具,例如compile插件是用来编译代码的工具,mybatis插件是用来自动生成数据库dao和mapper的工具。而依赖则是项目工程在编译过程中需要依赖的二方及三方包。
把开发项目看作做一道菜,代码就是作为原材料的菜,依赖就是油盐酱醋,而插件就是盘子和铁锅。依赖是整个项目的一部分,而插件不是。

待补充

参考:Maven教程

Maven基础 - 廖雪峰的官方网站

上一篇:使用 nohup java - jar 不输出nohup日志


下一篇:使用pdfbox将pdf转换成图片