zoukankan      html  css  js  c++  java
  • Java的Maven基础知识笔记:Maven是什么、maven目录、pom.xml唯一ID、maven解决依赖管理、maven中央仓库与镜像、构建流程(声明周期、阶段、目标)、使用插件、模块管理、mvnw指定版本、如何发布自己的开源库

      Maven是一个Java项目管理和构建工具,它可以定义项目结构、项目依赖,并使用统一的方式进行自动化构建,是Java项目不可缺少的工具。

    一、Maven介绍

    1、在了解Maven之前,我们先来看看一个Java项目需要的东西。

    (1)首先,我们需要确定引入哪些依赖包。例如,如果我们需要用到commons logging,我们就必须把commons logging的jar包放入classpath。如果我们还需要log4j,就需要把log4j相关的jar包都放到classpath中。这些就是依赖包的管理。

    (2)其次,我们要确定项目的目录结构。例如,src目录存放Java源码,resources目录存放配置文件,bin目录存放编译生成的.class文件。

    (3)此外,我们还需要配置环境,例如JDK的版本,编译打包的流程,当前代码的版本号。

    (4)最后,除了使用IDE进行编译外,我们还必须能通过命令行工具进行编译,才能够让项目在一个独立的服务器上编译、测试、部署。

      这些工作难度不大,但是非常琐碎且耗时。如果每一个项目都自己搞一套配置,肯定会一团糟。我们需要的是一个标准化的Java项目管理和构建工具。

    2、Maven就是专门为Java项目打造的标准化的项目管理和构建工具,它的主要功能有:

    • 提供了一套标准化的项目结构;
    • 提供了一套标准化的构建流程(编译,测试,打包,发布……);
    • 提供了一套依赖管理机制。

    3、一个使用Maven管理的普通的Java项目,它的目录结构默认如下:

    a-maven-project
    ├── pom.xml
    ├── src
    │   ├── main
    │   │   ├── java
    │   │   └── resources
    │   └── test
    │       ├── java
    │       └── resources
    └── target

      项目的根目录a-maven-project是项目名,它有一个项目描述文件pom.xml,存放Java源码的目录是src/main/java,存放资源文件的目录是src/main/resources,存放测试源码的目录是src/test/java,存放测试资源的目录是src/test/resources,最后,所有编译、打包生成的文件都放在target目录里。这些就是一个Maven项目的标准目录结构。

      所有的目录结构都是约定好的标准结构,我们千万不要随意修改目录结构。使用标准结构不需要做任何配置,Maven就可以正常使用。

    4、我们再来看最关键的一个项目描述文件pom.xml,它的内容长得像下面:

    <project ...>
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.itranswarp.learnjava</groupId>
        <artifactId>hello</artifactId>
        <version>1.0</version>
        <packaging>jar</packaging>
        <properties>
            ...
        </properties>
        <dependencies>
            <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.2</version>
            </dependency>
        </dependencies>
    </project>

      其中,groupId类似于Java的包名,通常是公司或组织名称,artifactId类似于Java的类名,通常是项目名称,再加上version,一个Maven工程就是由groupIdartifactIdversion作为唯一标识。我们在引用其他第三方库的时候,也是通过这3个变量确定。例如,依赖commons-logging

    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>

      使用<dependency>声明一个依赖后,Maven就会自动下载这个依赖包并把它放到classpath中。

    5、安装Maven:要安装Maven,可以从Maven官网下载最新的Maven,然后在本地解压,设置几个环境变量:

    M2_HOME=/path/to/maven-3.6.x
    PATH=$PATH:$M2_HOME/bin

      Windows可以把%M2_HOME%in添加到系统Path变量中。

    6、小结:

      Maven是一个Java项目的管理和构建工具:

      Maven使用pom.xml定义项目内容,并使用预设的目录结构;

      在Maven中声明一个依赖项可以自动下载并导入classpath;

      Maven使用groupIdartifactIdversion唯一定位一个依赖。

    二、依赖管理

    1、如果我们的项目依赖第三方的jar包,例如commons logging,那么问题来了:commons logging发布的jar包在哪下载?如果我们还希望依赖log4j,那么使用log4j需要哪些jar包?类似的依赖还包括:JUnit,JavaMail,MySQL驱动等等,一个可行的方法是通过搜索引擎搜索到项目的官网,然后手动下载zip包,解压,放入classpath。但是,这个过程非常繁琐。

      Maven解决了依赖管理问题。例如,我们的项目依赖abc这个jar包,而abc又依赖xyz这个jar包。当我们声明了abc的依赖时,Maven自动把abcxyz都加入了我们的项目依赖,不需要我们自己去研究abc是否需要依赖xyz

      因此,Maven的第一个作用就是解决依赖管理。我们声明了自己的项目需要abc,Maven会自动导入abc的jar包,再判断出abc需要xyz,又会自动导入xyz的jar包,这样,最终我们的项目会依赖abcxyz两个jar包。

      我们来看一个复杂依赖示例,当我们声明一个spring-boot-starter-web依赖时,Maven会自动解析并判断最终需要大概二三十个其他依赖,如果我们自己去手动管理这些依赖是非常费时费力的,而且出错的概率很大。

    2、Maven定义了几种依赖关系,分别是compiletestruntimeprovided

    scope说明示例
    compile 编译时需要用到该jar包(默认) commons-logging
    test 编译Test时需要用到该jar包 junit
    runtime 编译时不需要,但运行时需要用到 mysql
    provided 编译时需要用到,但运行时由JDK或某个服务器提供 servlet-api

      其中,默认的compile是最常用的,Maven会把这种类型的依赖直接放入classpath。

      test依赖表示仅在测试时使用,正常运行时并不需要。最常用的test依赖就是JUnit。

      runtime依赖表示编译时不需要,但运行时需要。最典型的runtime依赖是JDBC驱动,例如MySQL驱动:

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.48</version>
        <scope>runtime</scope>
    </dependency>

      provided依赖表示编译时需要,但运行时不需要。最典型的provided依赖是Servlet API,编译的时候需要,但是运行时,Servlet服务器内置了相关的jar,所以运行期不需要。

    3、中央仓库:Maven如何知道从何处下载所需的依赖?也就是相关的jar包?

      答案是Maven维护了一个中央仓库(repo1.maven.org),所有第三方库将自身的jar以及相关信息上传至中央仓库,Maven就可以从中央仓库把所需依赖下载到本地。

      Maven并不会每次都从中央仓库下载jar包。一个jar包一旦被下载过,就会被Maven自动缓存在本地目录(用户主目录的.m2目录),所以,除了第一次编译时因为下载需要时间会比较慢,后续过程因为有本地缓存,并不会重复下载相同的jar包。

    4、唯一ID:对于某个依赖,Maven只需要3个变量即可唯一确定某个jar包:

    • groupId:属于组织的名称,类似Java的包名;
    • artifactId:该jar包自身的名称,类似Java的类名;
    • version:该jar包的版本。

      通过上述3个变量,即可唯一确定某个jar包。Maven通过对jar包进行PGP签名确保任何一个jar包一经发布就无法修改。修改已发布jar包的唯一方法是发布一个新版本。因此,某个jar包一旦被Maven下载过,即可永久地安全缓存在本地。

    5、Maven镜像:除了可以从Maven的中央仓库下载外,还可以从Maven的镜像仓库下载。

      如果访问Maven的中央仓库非常慢,我们可以选择一个速度较快的Maven的镜像仓库。Maven镜像仓库定期从中央仓库同步:

               slow    ┌───────────────────┐
        ┌─────────────>│Maven Central Repo.│
        │              └───────────────────┘
        │                        │
        │                        │sync
        │                        ▼
    ┌───────┐  fast    ┌───────────────────┐
    │ User  │─────────>│Maven Mirror Repo. │
    └───────┘          └───────────────────┘

      中国区用户可以使用阿里云提供的Maven镜像仓库。使用Maven镜像仓库需要一个配置,在用户主目录下进入.m2目录,创建一个settings.xml配置文件,内容如下:

    <settings>
        <mirrors>
            <mirror>
                <id>aliyun</id>
                <name>aliyun</name>
                <mirrorOf>central</mirrorOf>
                <!-- 国内推荐阿里云的Maven镜像 -->
                <url>https://maven.aliyun.com/repository/central</url>
            </mirror>
        </mirrors>
    </settings>

    6、搜索第三方组件:如果我们要引用一个第三方组件,比如okhttp,如何确切地获得它的groupIdartifactIdversion

      方法是通过search.maven.org搜索关键字,找到对应的组件后,直接复制。

    7、命令行编译:在命令中,进入到pom.xml所在目录,输入以下命令:mvn clean package,如果一切顺利,即可在target目录下获得编译后自动打包的jar。

    8、小结:Maven通过解析依赖关系确定项目所需的jar包,常用的4种scope有:compile(默认),testruntimeprovided;Maven从中央仓库下载所需的jar包并缓存在本地;可以通过镜像仓库加速下载。

    三、构建流程

      Maven不但有标准化的项目结构,而且还有一套标准化的构建流程,可以自动化实现编译,打包,发布,等等。

    1、Lifecycle和Phase:使用Maven时,我们首先要了解什么是Maven的生命周期(lifecycle)。

      Maven的生命周期由一系列阶段(phase)构成,以内置的生命周期default为例,它包含以下phase:

        validate
        initialize
        generate-sources
        process-sources
        generate-resources
        process-resources
        compile
        process-classes
        generate-test-sources
        process-test-sources
        generate-test-resources
        process-test-resources
        test-compile
        process-test-classes
        test
        prepare-package
        package
        pre-integration-test
        integration-test
        post-integration-test
        verify
        install
        deploy

      如果我们运行mvn package,Maven就会执行default生命周期,它会从开始一直运行到package这个phase为止

        validate
        ...
        package

      如果我们运行mvn compile,Maven也会执行default生命周期,但这次它只会运行到compile

    2、Maven另一个常用的生命周期是clean,它会执行3个phase:

        pre-clean
        clean (注意这个clean不是lifecycle而是phase)
        post-clean

      所以,我们使用mvn这个命令时,后面的参数是phase,Maven自动根据生命周期运行到指定的phase。

    3、更复杂的例子是指定多个phase,例如,运行mvn clean package,Maven先执行clean生命周期并运行到clean这个phase,然后执行default生命周期并运行到package这个phase。

    4、在实际开发过程中,经常使用的命令有:

    mvn clean:清理所有生成的class和jar;
    
    mvn clean compile:先清理,再执行到compile;
    
    mvn clean test:先清理,再执行到test,因为执行test前必须执行compile,所以这里不必指定compile;
    
    mvn clean package:先清理,再执行到package。

      大多数phase在执行过程中,因为我们通常没有在pom.xml中配置相关的设置,所以这些phase什么事情都不做。经常用到的phase其实只有几个:

        clean:清理
        compile:编译
        test:运行测试
        package:打包

    5、执行一个phase又会触发一个或多个goal。goal的命名总是abc:xyz这种形式。

    执行的Phase对应执行的Goal
    compile compiler:compile
    test compiler:testCompile
    surefire:test

    6、其实我们类比一下就明白了:

    • lifecycle相当于Java的package,它包含一个或多个phase;

    • phase相当于Java的class,它包含一个或多个goal;

    • goal相当于class的method,它其实才是真正干活的

    7、小结:

      Maven通过lifecycle、phase和goal来提供标准的构建流程,可以使用:包 - 类 -方法 来类比理解这三者的关系。

      最常用的构建命令是指定phase,然后让Maven执行到指定的phase:

    • mvn clean
    • mvn clean compile
    • mvn clean test
    • mvn clean package

      通常情况,我们总是执行phase默认绑定的goal,因此不必指定goal。

    四、使用插件

    1、我们了解了Maven的lifecycle,phase和goal:

      使用Maven构建项目就是执行lifecycle,执行到指定的phase为止。

      每个phase会执行自己默认的一个或多个goal。

      goal是最小任务单元

    2、实际上,执行每个phase,都是通过某个插件(plugin)来执行的,Maven本身其实并不知道如何执行compile,它只是负责找到对应的compiler插件,然后执行默认的compiler:compile这个goal来完成编译。所以,使用Maven,实际上就是配置好需要使用的插件,然后通过phase调用它们。

    3、Maven通过自定义插件可以执行项目构建时需要的额外功能,使用自定义插件必须在pom.xml中声明插件及配置;

      插件会在某个phase被执行时执行;

      插件的配置和用法需参考插件的官方文档。

    五、模块管理

    1、在软件开发中,把一个大项目分拆为多个模块是降低软件复杂度的有效方法。

      对于Maven工程来说,原来是一个大项目:

    single-project
    ├── pom.xml
    └── src
    

      现在可以分拆成3个模块:

    mutiple-project
    ├── module-a
    │   ├── pom.xml
    │   └── src
    ├── module-b
    │   ├── pom.xml
    │   └── src
    └── module-c
        ├── pom.xml
        └── src
    

      Maven可以有效地管理多个模块,我们只需要把每个模块当作一个独立的Maven项目,它们有各自独立的pom.xml。例如,模块A的pom.xml

    2、比如模块A和模块B的pom.xml高度相似,因此,我们可以提取出共同部分作为parent。这样子模块B、子模块C都可以直接从parent继承,大幅简化了pom.xml的编写,如何继承,如下:

        <parent>
            <groupId>com.itranswarp.learnjava</groupId>
            <artifactId>parent</artifactId>
            <version>1.0</version>
            <relativePath>../parent/pom.xml</relativePath>
        </parent>

    3、如果模块A依赖模块B,则模块A需要模块B的jar包才能正常编译,我们需要在模块A中引入模块B

        ...
        <dependencies>
            <dependency>
                <groupId>com.itranswarp.learnjava</groupId>
                <artifactId>module-b</artifactId>
                <version>1.0</version>
            </dependency>
        </dependencies>

    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 http://maven.apache.org/maven-v4_0_0.xsd">
    
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.itranswarp.learnjava</groupId>
        <artifactId>build</artifactId>
        <version>1.0</version>
        <packaging>pom</packaging>
        <name>build</name>
    
        <modules>
            <module>parent</module>
            <module>module-a</module>
            <module>module-b</module>
            <module>module-c</module>
        </modules>
    </project>

      整体结构如下:

    multiple-project
    ├── pom.xml
    ├── parent
    │   └── pom.xml
    ├── module-a
    │   ├── pom.xml
    │   └── src
    ├── module-b
    │   ├── pom.xml
    │   └── src
    └── module-c
        ├── pom.xml
        └── src

    5、Maven支持模块化管理,可以把一个大项目拆成几个模块:

    • 可以通过继承在parent的pom.xml统一定义重复配置;
    • 可以通过<modules>编译多个模块。

    六、使用mvnw

    1、mvnw是Maven Wrapper的缩写。因为我们安装Maven时,默认情况下,系统所有项目都会使用全局安装的这个Maven版本。

      但是,对于某些项目来说,它可能必须使用某个特定的Maven版本,这个时候,就可以使用Maven Wrapper,它可以负责给这个特定的项目安装指定版本的Maven,而其他项目不受影响。

      简单地说,Maven Wrapper就是给一个项目提供一个独立的,指定版本的Maven给它使用。

    2、安装Maven Wrapper最简单的方式是在项目的根目录(即pom.xml所在的目录)下运行安装命令

    mvn -N io.takari:maven:0.7.6:wrapper

      如果要指定使用的Maven版本,使用下面的安装命令指定版本,例如3.3.3

    mvn -N io.takari:maven:0.7.6:wrapper -Dmaven=3.3.3

    七、发布Artifact - 把自己的库发布到Maven的repo中

      使用Maven发布一个Artifact时,有三种方法。

    1、可以发布到本地,然后由静态服务器提供repo服务,使用方必须声明repo地址;

    2、可以发布到central.sonatype.org,并自动同步到Maven中央仓库,需要前期申请账号以及本地配置;

    3、可以发布到GitHub Packages作为私有仓库使用,必须提供Token以及正确的权限才能发布和使用。

  • 相关阅读:
    【HDOJ】2774 Shuffle
    【POJ】2170 Lattice Animals
    【POJ】1084 Square Destroyer
    【POJ】3523 The Morning after Halloween
    【POJ】3134 Power Calculus
    【Latex】如何在Latex中插入伪代码 —— clrscode3e
    【HDOJ】4801 Pocket Cube 的几种解法和优化
    【HDOJ】4080 Stammering Aliens
    【HDOJ】1800 Flying to the Mars
    SQL语法
  • 原文地址:https://www.cnblogs.com/goloving/p/14818018.html
Copyright © 2011-2022 走看看