保姆级神器 Maven,不再用担忧项目构建搞崩了

2021年11月24日 阅读数:7
这篇文章主要向大家介绍保姆级神器 Maven,不再用担忧项目构建搞崩了,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

今天来给你们介绍一款项目构建神器——Maven,不只能帮咱们自动化构建,还可以抽象构建过程,提供构建任务实现;它跨平台,对外提供了一致的操做接口,这一切足以使它成为优秀的、流行的构建工具,今后之后,不再用担忧项目搞崩了。java

PS:为了可以帮助更多的 Java 爱好者,已将《Java 程序员进阶之路》开源到了 GitHub(本篇已收录)。该专栏目前已经收获了 675 枚星标,若是你也喜欢这个专栏,以为有帮助的话,能够去点个 star,这样也方便之后进行更系统化的学习:mysql

https://github.com/itwanger/toBeBetterJavaer

天天看着 star 数的上涨我内心很是的开心,但愿愈来愈多的 Java 爱好者能由于这个开源项目而受益,而愈来愈多人的 star,也会激励我继续更新下去~git

总结一下 Maven 的优势,主要有如下 3 点:程序员

  • 依赖管理:Maven 能帮助咱们解决软件包依赖的管理问题,再也不须要提交大量的 jar 包、引入第三方库;
  • 规范目录结构:Maven 标准的目录结构有助于项目构建的标准化,经过配置 profile 还能够根据不一样的环境(开发环境、测试环境,生产环境)读取不一样的配置文件;
  • 方便集成:可以集成在 IDE 中更方便使用。

1、安装 Maven

因为 JDK 是 Maven 安装的前置条件,因此请使用 java -version 确认是否已经安装了 JDK:github

我本人使用的是 macOS,因此能够有两种安装方式,一种官网下载,手动安装;一种直接使用 brew 一键安装web

咱们先介绍官网下载,手动安装,该方式一样适用于 Windows 系统,差异可参照 Maven 官网安装教程:spring

http://maven.apache.org/insta...

1)一种官网下载,手动安装sql

第一步,去官网下载 Maven 安装包:apache

官网地址: http://maven.apache.org/downl...

不少初学者在官网下载的时候不知道选哪个,这里作一下简单的介绍。编程

  • bin(binary)表明由 Java 源文件编译后的二进制 class 文件,src(source)表明Java 源文件。
  • 通常状况下,选择 bin 文件进行安装就 OK 了;若是你想本身编译,可选 src 版本。
  • tar.gz 压缩格式适用于 Unix 操做系统,zip 适用于 Windows 操做系统;但不是绝对的。

第二步,解压下载的安装包,复制该路径:

  • bin 目录:该包含了 Maven 运行的全部脚本,用来配置 Java 命令,准备执行环境,而后执行 Java 命令。
  • boot 目录:该目录只包含了一个 plexus-classworlds-xxx-jar 文件,该文件是一个类加载器框架,至关于默认的 Java 类加载器,提供了更加丰富的语法以便配置,Maven 使用该加载器加载本身的类库。
  • conf 目录:该目录包含了一个很是重要的文件 settings.xml。能够直接修改该文件,用来全局定制 Maven 的行为;也能够复制该文件到 ~/.m2/ 目录下(~表示用户目录),修改该文件能够在用户范围内定制 Maven 的行为。
  • lib 目录:该目录包含了Maven运行时所须要的 Java 类库,包括Maven 依赖的第三方类库,好比 slf4j-api.jar。

第三步,配置环境变量

打开终端,输入 vim ~/.bash_profile 命令打开 bash_profile 文件:

bash_profile 文件用于配置环境变量和启动程序,详细介绍可参照:

https://www.cnblogs.com/kevin...

在文件中添加设置环境变量的命令:

export M2_HOME=/Users/maweiqing/cmower/save/apache-maven-3.8.3
export PATH=${PATH}:${M2_HOME}/bin

保存后退出,能够执行 source ~/.bash_profile 使配置生效:

第四步,查看配置是否生效

输入 mvn -v 命令,若是输出如下内容,表示配置成功:

如未生效,可再开一个终端窗口尝试 mvn -v 命令。

2)brew 一键安装

第一步,使用 brew install maven 命令一键安装,并自动配置环境变量

第二步,使用 mvn -v 命令查看版本

2、Maven 配置文件大盘点

Maven 是基于 POM(Project Object Model) 进行的,项目的全部配置都会放在 pom.xml 文件中,包括项目的类型、名字,依赖关系,插件定制等等。

<?xml version="1.0" encoding="UTF-8"?>
<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.itwanger</groupId>
    <artifactId>MavenDemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>MavenDemo</name>
</project>
  • 第一行是XML头,指定了该xml文档的版本和编码方式。
  • project 是根元素,声明了一些POM相关的命名空间及xsd元素。
  • modelVersion指定了当前POM的版本,对于Maven 3来讲,值只能是4.0.0。
  • groupId定义了项目属于哪一个组织,一般是组织域名的倒序,好比说个人域名是 itwanger.com,因此groupId就是 com.itwanger。
  • artifactId定义了项目在组织中的惟一ID。
  • version指定了项目当前的版本,SNAPSHOT意为快照,说明该项目还处于开发中。
  • name 声明了一个对于用户更为友好的项目名称。

groupId、artifactId和version这三个元素定义了一个项目的基本坐标,在Maven的世界里,任何的jar和pom都是以基于这些坐标进行区分的。

<project>
...
<dependencies>
    <dependency>
        <groupId>实际项目</groupId>
     <artifactId>模块</artifactId>
     <version>版本</version>
     <type>依赖类型</type>
     <scope>依赖范围</scope>
     <optional>依赖是否可选</optional>
     <!—主要用于排除传递性依赖-->
     <exclusions>
         <exclusion>
           <groupId>…</groupId>
          <artifactId>…</artifactId>
       </exclusion>
     </exclusions>
  </dependency>
<dependencies>
...
</project>
  • dependencies 能够包含一个或者多个dependency元素,以声明一个或者多个项目依赖。
  • grounpId、artifactId和version 组成了依赖的基本坐标。
  • type 指定了依赖的类型,默认为 jar。
  • scope 指定了依赖的范围(详情见下面依赖范围部分)。
  • optional 标记了依赖是不是可选的(详情见下面依赖可选部分)。
  • exclusions 用来排除传递性依赖(详情见下面依赖排除部分)。

依赖范围有如下几种:

  • compile,默认的依赖范围,表示依赖须要参与当前项目的编译,后续的测试、运行周期也参与其中,是比较强的依赖。
  • test,表示依赖仅仅参与测试相关的工做,包括测试代码的编译和运行。比较典型的如 junit。
  • runntime,表示依赖无需参与到项目的编译,不事后期的测试和运行须要其参与其中。
  • provided,表示打包的时候能够不用包进去,别的容器会提供。和 compile 至关,可是在打包阶段作了排除的动做。
  • system,从参与程度上来讲,和 provided 相似,但不经过 Maven 仓库解析,可能会形成构建的不可移植,要谨慎使用。

关于传递性依赖

好比一个account-email项目为例,account-email有一个compile范围的spring-code依赖,spring-code有一个compile范围的commons-logging依赖,那么commons-logging就会成为account-email的compile的范围依赖,commons-logging是account-email的一个传递性依赖:

有了传递性依赖机制,在使用Spring Framework的时候就不用去考虑它依赖了什么,也不用担忧引入多余的依赖。Maven会解析各个直接依赖的POM,将那些必要的间接依赖,以传递性依赖的形式引入到当前的项目中。

关于依赖可选

项目中A依赖B,B依赖于X和Y,若是全部这三个的范围都是compile的话,那么X和Y就是A的compile范围的传递性依赖,可是若是我想X、Y不做为A的传递性依赖,不给它用的话,能够按照下面的方式配置可选依赖:

<project>  
    <modelVersion>4.0.0</modelVersion>  
    <groupId>com.itwanger</groupId>  
    <artifactId>project-b</artifactId>  
    <version>1.0.0</version>  
    <dependencies>  
        <dependency>  
            <groupId>mysql</groupId>  
            <artifactId>mysql-connector-java</artifactId>  
            <version>5.1.10</version>  
            <optional>true</optional>  
        </dependency>  
        <dependency>  
            <groupId>postgresql</groupId>  
            <artifactId>postgresql</groupId>  
            <version>8.4-701.jdbc3</version>  
            <optional>true</optional>  
        </dependency>  
    </dependencies>  
</project>

关于依赖排除

有时候你引入的依赖中包含你不想要的依赖包,你想引入本身想要的,这时候就要用到排除依赖了,好比下图中spring-boot-starter-web自带了logback这个日志包,我想引入log4j2的,因此我先排除掉logback的依赖包,再引入想要的包就好了。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.5.6</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!-- 使用 log4j2 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
    <version>2.5.6</version>
</dependency>

声明exclustion的时候只须要groupId和artifactId,不须要version元素,由于groupId和artifactId就能惟必定位某个依赖。

3、Maven 仓库

在 Maven 的术语中,仓库是一个位置(place),项目中依赖的第三方库以及插件(可统称为构件),都放在这里。全部的 Maven 项目均可以共享这个仓库,只须要根据依赖的坐标,就能够在须要的时候找到仓库中的依赖,并使用它们。

举个例子,项目中使用了分页插件的依赖:

<dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper-spring-boot-starter</artifactId>
      <version>1.1.0</version>
</dependency>

那么它对应的仓库路径是这样的:

仓库能够如下几种:

1)本地仓库

当Maven在执行编译或测试时,若是须要使用依赖文件,它老是基于坐标使用本地仓库的依赖文件。

默认状况下,无论是Window仍是macOS,或者是 Linux,每一个用户都会在本身的用户目录下有一个路径名为 .m2/repository/ 的仓库目录。

若是你想自定义本地仓库目录地址,能够编辑文件~/.m2/settings.xml,设置localRepository元素的值为你想要的仓库地址,例如:

<localRepository>/path/to/local/repo</localRepository>

若是找不到 ~/.m2/settings.xml 的话,能够到 Maven 的安装目录(前文提到的 conf 目录)下去拷贝。

2)远程仓库

默认状况下,本地仓库是被注释掉的,也就是空的,那么就必须得给 Maven 配置一个可用的远程仓库,不然 Maven 在 build(构建)的时候就没法去下载依赖。

中央仓库就是这样一个可用的远程仓库,里面包含了这个世界上绝大多数流行的开源 Java 类库,以及源码、做者信息、许可证信息等等。

不过,默认的中央仓库访问速度比较慢,一般咱们会选择使用阿里的 Maven 远程仓库。

<repositories>
    <repository>
        <id>ali-maven</id>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
            <updatePolicy>always</updatePolicy>
            <checksumPolicy>fail</checksumPolicy>
        </snapshots>
    </repository>
</repositories>
  • repositories 能够包含一个或者多个repository元素,以声明一个或者多个仓库。
  • id,仓库声明的惟一id,须要注意的是,Maven自带的中央仓库使用的id为central,若是其余仓库也使用了该id,就会覆盖中央仓库的配置。
  • url,指向了仓库的地址。
  • releases和snapshots,用来控制Maven对于发布版构件和快照版构件的下载权限。
  • enabled子元素为 true 时表示能够从仓库下载发布版构件和快照版构件。
  • updatePolicy 子元素用来配置Maven从远处仓库检查更新的频率。

    • 默认值是daily,表示天天检查一次;
    • 可选值 never 表示从不检查;
    • 可选值always表示每次构建时检查更新;
    • 可选值interval表示每隔X分钟检查一次更新(X为任意整数)。
  • checksumPolicy 子元素用来配置Maven检查校验的策略。在下载构件的时候,Maven会去校验,若是校验失败,

    • 当checksumPolicy的值为默认的warn时,Maven会在执行构建时输出警告信息;
    • 值为fail 时,Maven遇到校验错误就让构建失败;
    • 值为ignore时,Maven将彻底忽略校验。

搭建远程仓库的另一个目的是方便部署咱们本身的项目构件至远程仓库供其余团队成员使用,这时候须要配置distributionManagement元素:

<distributionManagement>
        <repository>
            <id>releases</id>
            <name>public</name>
            <url>http://59.50.95.66:8081/nexus/content/repositories/releases</url>
        </repository>
        <snapshotRepository>
            <id>snapshots</id>
            <name>Snapshots</name>
            <url>http://59.50.95.66:8081/nexus/content/repositories/snapshots</url>
        </snapshotRepository>
</distributionManagement>
  • repository表示发布版本构件的仓库。
  • snapshotRepository 表示快照版本(开发测试用)的仓库。
  • 这两个元素都须要配置id、name和url,id为远程仓库的惟一标识,name是为了方便阅读,url表示仓库的地址。

配置好了之后运行命令 mvn clean deploy,Maven就会将项目部署到对应的远程仓库。项目是快照仍是发布版本经过以前远程仓库配置项中的 releases 和 snapshots 来区分。

3)仓库镜像

若是仓库X能够提供仓库Y存储的全部内容,那么就能够认为X是Y的一个镜像。一般咱们会在 settings.xml 文件中添加阿里云镜像:

<mirrors>
    <mirror>
      <id>alimaven</id>
      <name>aliyun maven</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
      <mirrorOf>central</mirrorOf>        
    </mirror>
  </mirrors>

其中 mirrorOf 元素的可选项有:

  • <mirrorOf>*</mirrorOf>,匹配全部远程仓库。
  • <mirrorOf>external:*</mirrorOf>,匹配全部远程仓库,使用localhost的除外,使用 file:// 协议的除外。也就是说,匹配全部不在本机上的远程仓库。
  • <mirrorOf>repo1,repo2</mirrorOf>,匹配仓库repo1和repo2,使用逗号分隔多个远程仓库。
  • <mirrorOf>*,!repo1<mirrorOf>,匹配全部远程仓库,repo1除外,使用感叹号将仓库从匹配中排除。

上例中 <mirrorOf>central</mirrorOf> 表示任何对于中央仓库的请求都会转至该镜像。

4)私服

私服是一种特殊的远程仓库,它架设在局域网内中,私服代理广域网上的远程仓库,供局域网内的Maven用户使用。当Maven须要下载构件的时候,先从私服请求,若是私服上不存在该构件,则从外部的远程仓库下载,并缓存到私服上。

私服有如下好处:

  • 节省外网访问速度
  • 加速Maven构建
  • 提升稳定性,加强控制
  • 下降中央仓库的负荷

5)仓库服务搜索

推荐 2 个提供仓库搜索服务的网站:

4、使用 Maven

1)Maven 常见命令

  • mvn clean:表示运行清理操做(会默认把target文件夹中的数据清理)。
  • mvn clean compile:表示先运行清理以后运行编译,会将代码编译到target文件夹中。
  • mvn clean test:运行清理和测试。
  • mvn clean package:运行清理和打包。
  • mvn clean install:运行清理和安装,会将打好的包安装到本地仓库中,以便其余的项目能够调用。
  • mvn clean deploy:运行清理和发布(发布到私服上面)。

2)Maven 经常使用 POM 属性

  • ${project.build.sourceDirectory}:项目的主源码目录,默认为src/main/java/
  • ${project.build.testSourceDirectory}:项目的测试源码目录,默认为 /src/test/java/
  • ${project.build.directory}:项目构建输出目录,默认为 target/
  • ${project.build.outputDirectory}:项目主代码编译输出目录,默认为 target/classes/
  • ${project.build.testOutputDirectory}:项目测试代码编译输出目录,默认为 target/testclasses/
  • ${project.groupId}:项目的 groupId.
  • ${project.artifactId}:项目的 artifactId.
  • ${project.version}:项目的 version,于 ${version} 等价
  • ${project.build.finalName}:项目打包输出文件的名称,默认为${project.artifactId}${project.version}

3)Intellij IDEA 配置 Maven

4)Maven 经常使用插件

插件是Maven的核心功能,它容许在多个项目中重用通用的构建逻辑。插件可用于:

  • 建立jar文件,
  • 建立war文件,
  • 编译代码,
  • 单元测试代码,
  • 建立项目文档等。

经常使用的插件有:

  • maven-antrun-plugin,让用户在 Maven 项目中运行 Ant 任务。用户能够直接在该插件的配置以 Ant 的方式编写 Target,而后交给该插件的 run 目标去执行。在一些由 Ant 往 Maven 迁移的项目中,该插件尤为有用。此外当你发现须要编写一些自定义程度很高的任务,同时又以为 Maven 不够灵活时,也能够以 Ant 的方式实现之。maven-antrun-plugin 的 run 目标一般与生命周期绑定运行。
  • maven-assembly-plugin,制做项目分发包,该分发包可能包含了项目的可执行文件、源代码、readme、平台脚本等等。maven-assembly-plugin 支持各类主流的格式如 zip、tar.gz、jar 和 war 等,具体打包哪些文件是高度可控的,例如用户能够按文件级别的粒度、文件集级别的粒度、模块级别的粒度、以及依赖级别的粒度控制打包,此外,包含和排除配置也是支持的。maven-assembly-plugin 要求用户使用一个名为assembly.xml的元数据文件来表述打包,它的 single 目标能够直接在命令行调用,也能够被绑定至生命周期。
  • maven-help-plugin,一个小巧的辅助工具,最简单的help:system能够打印全部可用的环境变量和 Java 系统属性。help:effective-pom和help:effective-settings最为有用,它们分别打印项目的有效 POM 和有效 settings,有效 POM 是指合并了全部父 POM(包括 Super POM)后的 XML,当你不肯定 POM 的某些信息从何而来时,就能够查看有效 POM。
  • maven-javadoc-plugin,javadoc 插件,将源码的 javadoc 发布出去。

参考连接:

嘟嘟MD: http://tengj.top/2018/01/01/m...
杭建:《Java 工程师修炼之道》
许晓斌: https://www.infoq.cn/article/...

但愿你们能在阅读完本篇文章后对 Maven 有一个初步的了解和掌握,并将这些技能在项目的实战中加以练习,以达到项目工程化的要求。

这是《Java 程序员进阶之路》专栏的第 72 篇(记得去点个 star 哦)。该专栏风趣幽默、通俗易懂,对 Java 爱好者极度友好和温馨😄,内容包括但不限于 Java 基础、Java 集合框架、Java IO、Java 并发编程、Java 虚拟机、Java 企业级开发(SSM、Spring Boot)等核心知识点

https://github.com/itwanger/toBeBetterJavaer


让咱们一块儿成为更好的 Java 工程师吧!