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以及正确的权限才能发布和使用。

  • 相关阅读:
    Spring MVC中@ControllerAdvice注解实现全局异常拦截
    IDEA一个窗口打开多个项目
    IntelliJ IDEA中Spring Boot项目使用spring-boot-devtools无法实现热部署/热更新的问题解决
    Java中String/StringBuffer/StringBuilder区别(转)
    IDEA查看源码时提示:Library source does not match the bytecode for class的问题分析
    忙的一天的复盘
    Apollo专题
    使用Spring JPA中Page、Pageable接口和Sort类完成分页排序【专题】
    公众号开发之wx-tools+springboot应用实战-音乐爬虫推送[JAVA]
    [LeetCode] 152. Maximum Product Subarray 求最大子数组乘积
  • 原文地址:https://www.cnblogs.com/goloving/p/14818018.html
Copyright © 2011-2022 走看看