Maven

Maven介绍

Maven 翻译为"专家"、"内行",是 Apache 下的一个纯 Java 开发的开源项目。基于项目对象模型(缩写:POM)概念,Maven利用一个中央信息片断能管理一个项目的构建、报告和文档等步骤。

Maven 是一个项目管理工具,可以对 Java 项目进行构建、依赖管理。

Maven 也可被用于构建和管理各种项目,例如 C#,Ruby,Scala 和其他语言编写的项目。Maven 曾是 Jakarta 项目的子项目,现为由 Apache 软件基金会主持的独立 Apache 项目。

maven的功能:

  • 构建、文档生成、报告、依赖、SCMs、发布、分发、邮件列表
  • 打包文件,形成jar文件或者war文件。

Maven的构建

构建是一些步骤的统称,例如项目代码的编译、测试、运行、打包、部署等。

maven支持的构建包括:

  1. 清理clean:把之前项目编译的东西删除掉,为新的编译代码作准备。
  2. 编译compile:把程序代码编译成可执行文件,java-class文件。批量的,可以同时将多个文件编译成class。
  3. 测试test:maven可以执行测试程序代码,验证功能是否正确,批量的,同时测试很多功能。
  4. 报告:生成的测试结果文件,测试报告。
  5. 打包package:把项目中所有的class文件、配置文件等所有资源放到一个压缩文件中。java程序通常是jar扩展名的,对于web应用扩展名通常是.war。
  6. 安装install:把步骤5中生成的文件安装到本机仓库。
  7. 部署deploy

Maven的安装

  1. maven官网下载安装文件。Maven官网

  2. 解压缩安装包,到自己指定的非中文目录。

  3. 设置 Maven 环境变量

    添加环境变量 MAVEN_HOME:

    右键 "计算机",选择 "属性",之后点击 "高级系统设置",点击"环境变量",来设置环境变量,有以下系统变量需要配置:新建系统变量 MAVEN_HOME,变量值:E:\Maven\apache-maven-3.3.9

编辑系统变量 Path,添加变量值:;%MAVEN_HOME%\bin

  1. 验证是否安装成功。打开终端输入mvn -v。正常会输出Maven版本信息、java版本信息和系统信息。如下:

    C:\Users\lowell>mvn -v
    Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
    Maven home: D:\apache-maven-3.6.3\bin\..
    Java version: 14.0.1, vendor: Oracle Corporation, runtime: C:\Java\jdk-14.0.1
    Default locale: zh_CN, platform encoding: GBK
    OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
    

解压后的子目录:

  • bin:存放可执行程序,主要是mvn.cmd

  • conf:maven工具本身的配置文件settings.xml

    本地仓库默认是在: ${user.home}/.m2/repository,即C:/User/用户名/.m2/repository中。

    通过conf文件可以修改本地仓库的地址

    <localRepository>你的仓库的地址</localRepository>
    

Maven的核心概念

POM

POM 代表工程对象模型。它是使用 Maven 工作时的基本组建,是一个 xml 文件。它被放在工程根目录下,文件命名为 pom.xml。

POM 包含了关于工程和各种配置细节的信息,Maven 使用这些信息构建工程。

POM 也包含了目标和插件。当执行一个任务或者目标时,Maven 会查找当前目录下的 POM,从其中读取所需要的配置信息,然后执行目标。能够在 POM 中设置的一些配置如下:

  • project dependencies
  • plugins
  • goals
  • build profiles
  • project version
  • developers
  • mailing list

在创建 POM 之前,我们首先确定工程组(groupId),及其名称(artifactId)和版本,在仓库中这些属性是工程的唯一标识。

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
   http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <groupId>com.companyname.project-group</groupId>
   <artifactId>project</artifactId>
   <version>1.0</version>

</project>

需要说明的是每个工程应该只有一个 POM 文件。

  • 所有的 POM 文件需要 project 元素和三个必须的字段:groupId, artifactId,version
  • 在仓库中的工程标识为 groupId:artifactId:version
  • POM.xml 的根元素是 project,它有三个主要的子节点:
节点 描述
modelVersion Maven模型的版本,对于Maven2和Maven3来说只能是4.0.0
groupId 这是工程组的标识。它在一个组织或者项目中通常是唯一的。例如,一个银行组织 com.company.bank 拥有所有的和银行相关的项目。
artifactId 这是工程的标识。它通常是工程的名称。例如,消费者银行。groupId 和 artifactId 一起定义了 artifact 在仓库中的位置。
version 这是工程的版本号。在 artifact 的仓库中,它用来区分不同的版本。例如: com.company.bank:consumer-banking:1.0 com.company.bank:consumer-banking:1.1.
packaging 项目打包的类型,jar、war、ear等,默认是jar
dependencies和dependency dependency来配置项目中的依赖,以坐标来定位。
properties 用来定义一些配置属性,<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>防止中文乱码。
build 与构建相关的配置,比如:编译插件的jdk版本,在properties中也可以设置。

约定的目录结构

Maven项目的目录和文件的位置都是规定的。

|项目名/
--|src
----|main   # 放主程序java代码和配置文件
-------|java  # 程序包和包中的java文件
-------|resources  # java程序中使用的配置文件(图片/属性等)
----|test    # 放测试程序用到的文件
-------|java  # 测试程序包和包中的java文件
-------|resources  # java程序中使用的配置文件(图片/属性等)
--|pom.xml   # maven的核心文件,maven项目必须有

坐标

是一个唯一的字符串,用来表示资源的。Maven使用一组向量组成坐标来表示。

  • groupId:组织名,通常是公司或者组织域名倒序+项目名称
  • artifactId:模块名,通常是工程名。
  • version:版本号

项目在仓库中的位置是由坐标决定:groupId、artifactId、version决定项目在仓库总的路径,artifactId和version决定jar包的名称。

依赖管理

管理项目中所使用的的jar文件

仓库管理

什么是 Maven 仓库?

在 Maven 的术语中,仓库是一个位置(place),例如目录,可以存储所有的工程 jar 文件、library jar 文件、插件或任何其他的工程指定的文件。

Maven 仓库有三种类型:

  • 本地(local)
  • 中央(central)
  • 远程(remote)

本地仓库

Maven 本地仓库是机器上的一个文件夹。它在你第一次运行任何 maven 命令的时候创建。

Maven 本地仓库保存你的工程的所有依赖(library jar、plugin jar 等)。当你运行一次 Maven 构建,Maven 会自动下载所有依赖的 jar 文件到本地仓库中。它避免了每次构建时都引用存放在远程机器上的依赖文件。

Maven 本地仓库默认被创建在 %USER_HOME% 目录下。要修改默认位置,在 %M2_HOME%\conf 目录中的 Maven 的 settings.xml 文件中定义另一个路径。

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 
   http://maven.apache.org/xsd/settings-1.0.0.xsd">
      <localRepository>C:/MyLocalRepository</localRepository>
</settings>

当你运行 Maven 命令,Maven 将下载依赖的文件到你指定的路径中。

中央仓库

Maven 中央仓库是由 Maven 社区提供的仓库,其中包含了大量常用的库。

中央仓库的关键概念:

  • 这个仓库由 Maven 社区管理。
  • 不需要配置。
  • 需要通过网络才能访问。

要浏览中央仓库的内容,maven 社区提供了一个 URL:http://search.maven.org/#browse。使用这个仓库,开发人员可以搜索所有可以获取的代码库。

远程仓库

如果 Maven 在中央仓库中也找不到依赖的库文件,它会停止构建过程并输出错误信息到控制台。为避免这种情况,Maven 提供了远程仓库的概念,它是开发人员自己定制仓库,包含了所需要的代码库或者其他工程中用到的 jar 文件。

举例说明,使用下面的 POM.xml,Maven 将从远程仓库中下载该 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
   http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.companyname.projectgroup</groupId>
   <artifactId>project</artifactId>
   <version>1.0</version>
   <dependencies>
      <dependency>
         <groupId>com.companyname.common-lib</groupId>
         <artifactId>common-lib</artifactId>
         <version>1.0.0</version>
      </dependency>
   <dependencies>
   <!--构建远程仓库-->
   <repositories>
      <repository>
         <id>companyname.lib1</id>
         <url>http://download.companyname.org/maven2/lib1</url>
      </repository>
      <repository>
         <id>companyname.lib2</id>
         <url>http://download.companyname.org/maven2/lib2</url>
      </repository>
   </repositories>
</project>

Maven 依赖搜索顺序

当我们执行 Maven 构建命令时,Maven 开始按照以下顺序查找依赖的库:

  • 步骤 1 - 在本地仓库中搜索,如果找不到,执行步骤 2,如果找到了则执行其他操作。
  • 步骤 2 - 在中央仓库中搜索,如果找不到,并且有一个或多个远程仓库已经设置,则执行步骤 4,如果找到了则下载到本地仓库中已被将来引用。
  • 步骤 3 - 如果远程仓库没有被设置,Maven 将简单的停滞处理并抛出错误(无法找到依赖的文件)。
  • 步骤 4 - 在一个或多个远程仓库中搜索依赖的文件,如果找到则下载到本地仓库已被将来引用,否则 Maven 将停止处理并抛出错误(无法找到依赖的文件)。

生命周期

maven工具构建项目的过程,就是生命周期。

当 Maven 开始构建工程,会按照所定义的阶段序列的顺序执行每个阶段注册的目标。Maven 有以下三个标准的生命周期:

  • clean
  • default(or build)
  • site

clean生命周期

当 mvn clean 命令执行时,Maven 删除了构建目录。把之前项目编译的东西删除掉,为新的编译代码作准备。

如下图:编译之后会生成target目录。

执行mvn clean就会清除该目录。

Default (or Build) 生命周期

这是 Maven 的主要生命周期,被用于构建应用。包括下面的 23 个阶段。

生命周期阶段 描述
validate 检查工程配置是否正确,完成构建过程的所有必要信息是否能够获取到。
initialize 初始化构建状态,例如设置属性。
generate-sources 生成编译阶段需要包含的任何源码文件。
process-sources 处理源代码,例如,过滤任何值(filter any value)。
generate-resources 生成工程包中需要包含的资源文件。
process-resources 拷贝和处理资源文件到目的目录中,为打包阶段做准备。
compile 编译工程源码。
process-classes 处理编译生成的文件,例如 Java Class 字节码的加强和优化。
generate-test-sources 生成编译阶段需要包含的任何测试源代码。
process-test-sources 处理测试源代码,例如,过滤任何值(filter any values)。
test-compile 编译测试源代码到测试目的目录。
process-test-classes 处理测试代码文件编译后生成的文件。
test 使用适当的单元测试框架(例如JUnit)运行测试。
prepare-package 在真正打包之前,为准备打包执行任何必要的操作。
package 获取编译后的代码,并按照可发布的格式进行打包,例如 JAR、WAR 或者 EAR 文件。
pre-integration-test 在集成测试执行之前,执行所需的操作。例如,设置所需的环境变量。
integration-test 处理和部署必须的工程包到集成测试能够运行的环境中。
post-integration-test 在集成测试被执行后执行必要的操作。例如,清理环境。
verify 运行检查操作来验证工程包是有效的,并满足质量要求。
install 安装工程包到本地仓库中,该仓库可以作为本地其他工程的依赖。
deploy 拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程。

当一个阶段通过 Maven 命令调用时,例如 mvn compile,只有该阶段之前以及包括该阶段在内的所有阶段会被执行。

不同的 maven 目标将根据打包的类型(JAR / WAR),被绑定到不同的 Maven 生命周期阶段。

JAR是普通的java项目,WAR是java web项目。

Site 生命周期

Maven Site 插件一般用来创建新的报告文档、部署站点等。

插件和目标

maven工具构建项目时用到的插件。jar文件等。

命令行创建MAVEN项目

使用命令mvn archetype:generate创建maven项目

mvn archetype:generate # 交互式

输入完成之后,可能需要等待一会。之后会选择archetype,然后输入groupId、artifactId、version信息。

官方推荐groupId和package使用相同的路径

常用archetype

  • maven-archetype-quickstart()
  • maven-archetype-webapp(一个简单的Java Web应用程序)
  • maven-archetype-simple

maven中测试文件的示例

package org.lowell;

import static org.junit.Assert.assertTrue;

import org.junit.Test;

/**
 * Unit test for simple App.
 */
public class AppTest 
{
    /**
     * Rigorous Test :-)
     */
    @Test
    public void shouldAnswerWithTrue()
    {
        assertTrue( true );
    }
}

通过idea使用maven

File--》settings--》Build,Excution,Deployment--》Build Tools--》Maven

Maven home directory:Maven的安装目录

User settings file:就是maven安装目录conf/settings.xml配置文件

Local repository:本机仓库的目录位置

maven项目创建时,会联网下载模板,比较大,时间较长,使用如下参数不用下载

File--》settings--》Build,Excution,Deployment--》Build Tools--》Maven--》Runner--》

VM Options:-DarchetypeCatalog=internal

Maven的外部依赖

现在,如你所知道的,Maven的依赖管理使用的是 Maven - 仓库的概念。但是如果在远程仓库和中央仓库中,依赖不能被满足,如何解决呢? Maven 使用外部依赖的概念来解决这个问题。

  • 在 src 文件夹下添加 lib 文件夹
  • 复制任何 jar 文件到 lib 文件夹下。我们使用的是 ldapjdk.jar ,它是为 LDAP 操作的一个帮助库

现在你有了自己的工程库(library),通常情况下它会包含一些任何仓库无法使用,并且 maven 也无法下载的 jar 文件。如果你的代码正在使用这个库,那么 Maven 的构建过程将会失败,因为在编译阶段它不能下载或者引用这个库。

为了处理这种情况,让我们用以下方式,将这个外部依赖添加到 maven 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 
                             http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.companyname.bank</groupId>
    <artifactId>consumerBanking</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>consumerBanking</name>
    <url>http://maven.apache.org</url>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>ldapjdk</groupId>
            <artifactId>ldapjdk</artifactId>
            <scope>system</scope>
            <version>1.0</version>
            <systemPath>${basedir}\src\lib\ldapjdk.jar</systemPath>
        </dependency>
    </dependencies>

</project>

上例中, <dependencies> 的第二个 <dependency> 元素 , 阐明了外部依赖的关键概念。

  • 外部依赖(library jar location)能够像其他依赖一样在 pom.xml 中配置。
  • 指定 groupId 为 library 的名称。
  • 指定 artifactId 为 library 的名称。
  • 指定作用域(scope)为系统。
  • 指定相对于工程位置的系统路径。

Maven的依赖范围

  • maven的依赖范围包括: compile,provide,runtime,test,system。
  1. 编译依赖范围(compile),该范围就是默认依赖范围,此依赖范围对 于编译、测试、运行三种classpath都有效,举个简单的例子,假如项目中有spring-core的依赖,那么spring-core不管是在编译,测试,还是运行都会被用到,因此spring-core必须是编译范围(构件默认的是编译范围,所以依赖范围是编译范围的无须显示指定)
  2. 测试依赖范围(test),顾名思义就是针对于测试的,使用此依赖范围的依赖,只对测试classpath有效,在编译主代码和项目运行时,都将无法使用该依赖,最典型的例子就是 Junit, 构件在测试时才需要,所以它的依赖范围是测试,因此它的依赖范围需要显示指定为test ,当然不显示指定依赖范围也不会报错,但是该依赖会被加入到编译和运行的classpath中,造成不必要的浪费 。
  3. 已提供依赖范围(provided),使用该依赖范围的maven依赖,只对编译和测试的classpath有效,对运行的classpath无效,典型的例子就是servlet-api, 编译和测试该项目的时候需要该依赖,但是在运行时,web容器已经提供的该依赖,所以运行时就不再需要此依赖,如果不显示指定该依赖范围,并且容器依赖的版本和maven依赖的版本不一致的话,可能会引起版本冲突,造成不良影响。
  4. 运行时依赖范围(runtime),使用该依赖范围的maven依赖,只对测试和运行的classpath有效,对编译的classpath无效,典型例子就是JDBC的驱动实现,项目主代码编译的时候只需要JDK提供的JDBC接口,只有在测试和运行的时候才需要实现上述接口的具体JDBC驱动。
  5. 系统依赖范围(system),该依赖与classpath的关系与 provided依赖范围完全一致,但是系统依赖范围必须通过配置systemPath元素来显示指定依赖文件的路径,此类依赖不是由maven仓库解析的,而且往往与本机系统绑定,可能造成构件的不可移植,因此谨慎使用,systemPath元素可以引用环境变量:
  6. 导入依赖范围(import),该依赖范围不会对三种classpath产生影响,该依赖范围只能与dependencyManagement元素配合使用,其功能为将目标pom文件中dependencyManagement的配置导入合并到当前pom的dependencyManagement中。

Maven - 工程文档

本教程将教你如何创建应用程序的文档。那么让我们开始吧,在项目目录下,执行以下 mvn 命令。

D:\myweb>mvn site

Maven - 快照

大型软件应用程序通常由多个模块组成,这是多个团队工作于同一应用程序的不同模块的常见场景。例如一个团队工作负责应用程序的前端应用用户接口工程(app-ui.jar:1.0)),同时他们使用数据服务工程(data-service.jar:1.0)。

现在负责数据服务的团队可能正在进行修正 bug 或者增强功能,并快速迭代,然后他们几乎每天都会 release 工程库文件到远程仓库中。

现在如果数据服务团队每天上传新的版本,那么就会有下面的问题:

  • 每次数据服务团队发布了一版更新的代码时,都要告诉应用接口团队。
  • 应用接口团队需要定期更新他们的 pom.xml 来得到更新的版本

为了解决这样的情况,快照概念发挥了作用.

什么是快照?

快照是一个特殊的版本,它表示当前开发的一个副本。与常规版本不同,Maven 为每一次构建从远程仓库中检出一份新的快照版本。

现在数据服务团队会将每次更新的代码的快照(例如 data-service:1.0-SNAPSHOT)发布到仓库中,来替换旧的快照 jar 文件。

快照 vs 版本

对于版本,Maven 一旦下载了指定的版本(例如 data-service:1.0),它将不会尝试从仓库里再次下载一个新的 1.0 版本。想要下载新的代码,数据服务版本需要被升级到 1.1。

对于快照,每次用户接口团队构建他们的项目时,Maven 将自动获取最新的快照(data-service:1.0-SNAPSHOT)。

应用用户接口 pom.xml

应用用户接口工程正在使用 1.0 版本的数据服务的快照

<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>app-ui</groupId>
  <artifactId>app-ui</artifactId>
  <version>1.0</version>
  <packaging>jar</packaging>
  <name>health</name>
  <url>http://maven.apache.org</url>
  <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
     <dependency>
     <groupId>data-service</groupId>
         <artifactId>data-service</artifactId>
         <version>1.0-SNAPSHOT</version>
         <scope>test</scope>
     </dependency>
  </dependencies>
</project>

数据服务 pom.xml

数据服务工程为每个微小的变化 release 1.0 快照

<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>data-service</groupId>
  <artifactId>data-service</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>health</name>
  <url>http://maven.apache.org</url>
  <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  </project>

虽然,对于快照,Maven 每次自动获取最新的快照,但你可以在任何 maven 命令中使用 -U 参数强制 maven 下载最新的快照。

mvn clean package -U

让我们打开命令控制台,进入 C:\ > MVN > app-ui 目录并执行以下 mvn 命令。

C:\MVN\app-ui>mvn clean package -U

Maven将在下载数据服务的最新快照后,开始构建工程。

Maven全局变量

  1. 在properties中通过自定义标签声明变量(标签名就是变量名)
  2. 在pom.xml其他位置使用${标签名}使用变量的值。

资源插件

  1. pom.xml中没有使用resources的时候,默认只将resources中的文件拷贝到target/classes中,不会将其他目录下的非java文件拷贝到target/classes的目录中。

  2. 有些需要把非java文件放到src/main/java目录下,当执行项目时,需要用到src/main/java目录下的文件,需要告诉maven在编译程序时将src/main/java下的非java文件也拷贝到target/classes目录中。此时就需要在pom.xml文件中使用

    <build>
    	<resources></resources>
    </build>
    

    示例

    <build>
        <resources>
          <resource>
            <directory>src/main/java</directory> <!--文件所在目录-->
            <includes>
              <include>**/*.txt</include>
            </includes>
            <!--不启用过滤器,*.txt已经起到过滤作用-->
            <filtering>false</filtering>
          </resource>
        </resources>
    </build>
    

Maven多模块管理(继承)

maven父工程必须遵循以下两点要求

  • packaging标签中的文本内容必须是pom
  • 把src删除掉

maven多模块管理其实就是让他的子模块中的pom文件继承父模块的pom文件

posted @ 2020-09-13 21:57  Lowell  阅读(148)  评论(0)    收藏  举报