51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

你真的了解Maven吗?

# (一)什么是Maven {#一-什么是maven}

Maven是Apache下的一个开源项目,目前可以用于构建和管理任何基于 Java 的项目的工具,让 Java 开发人员的日常工作更轻松。为了让开发人员更轻松,Maven做到了以下几点:

# 简化构建过程 {#简化构建过程}

提供了标准的、跨平台的自动化项目构建方式。Maven 并没有消除了解底层机制的需要,但是Maven确实让Java项目的构建变得更简单了。

# 提供统一的构建系统 {#提供统一的构建系统}

Maven 使用其项目对象模型 (POM) 和一组插件来构建项目。一旦你熟悉了一个 Maven 项目,你就会知道所有的 Maven 项目是如何构建的。这在浏览开源项目和其他项目时会十分节省时间。

# 依赖管理 {#依赖管理}

更加方便快捷地管理项目依赖的Jar包,同时可避免不同Jar包版本之间的冲突。

# (二)Maven中的基础概念 {#二-maven中的基础概念}

# 仓库 {#仓库}

仓库中存储了各种Jar包,Maven本身维护了一个包含全球大部分Jar包的仓库,称为中央仓库,可以在Maven提供的网站中搜索需要的Jar包:https://search.maven.org/。

每个人的本地也会有一个Maven仓库称为本地仓库,当我们使用一些Jar包时,需要先从中央仓库拉取Jar包到本地仓库,再从本地仓库拉取到项目中。

一些公司为了更快的访问速度以及方便将本公司的Jar包给员工使用,会搭建 Maven私服仓库,私服仓库会定期读取中央仓库,也会维护自身的Jar包在里面。

# 坐标 {#坐标}

坐标是用来描述maven中每个资源的位置,坐标主要通过三个标签来定位到一个资源:比如我上传到中仓仓库的一个Jar包:

<dependency>
  <groupId>io.github.oliverliy</groupId>
  <artifactId>fast-sso-client</artifactId>
  <version>0.0.2</version>  </dependency>

groupId:当前Jar包所属的机构,通常采用域名反写的方式,我这里是使用了github的域名。

artifactId:当前项目名称,我上传的这个项目名称就叫fast-sso-client。

version:定义当前的项目版本。

# (三)Maven中的依赖管理 {#三-maven中的依赖管理}

依赖是指一个项目所需的所有Jar包,在Maven中,统一将依赖放在dependencies下的dependency中。

<dependencies>
    <dependency>
      <groupId>io.github.oliverliy</groupId>
      <artifactId>fast-sso-client</artifactId>
      <version>0.0.2</version>
    </dependency></dependencies>

# 4.1 依赖传递 {#_4-1-依赖传递}

Maven中的依赖具备依赖传递的功能,比如在上面这个例子中引入了fast-sso-client这个依赖包,而fast-sso-client又会依赖其他的Jar包,就如下图所示:

直接引入的依赖包称为直接依赖,被直接依赖带入项目的其他依赖包称为间接依赖。

# 4.2 依赖冲突 {#_4-2-依赖冲突}

当一个项目中同时存在多个版本的依赖包时,就会出现依赖冲突的情况。Maven项目在选择依赖包时,会采取就近原则的方式。配置顺序靠前的会替换配置顺序靠后的,配置层级浅的会替换配置层级深的。

以上面这个依赖关系图来看,最终项目A依赖的Jar包分别是:1.0版本的依赖A和1.0版本的依赖B。

# 4.3 依赖冲突 {#_4-3-依赖冲突}

如果想在项目中排除掉依赖包中的某个传递依赖时,可以通过exclude排除掉依赖。被排除的依赖无需指定版本。

<dependency>
    <groupId>io.github.oliverliy</groupId>
    <artifactId>fast-sso-client</artifactId>
    <version>0.0.2</version>
    <exclusions>
        <exclusion>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </exclusion>
    </exclusions></dependency>

# 4.4 依赖范围 {#_4-4-依赖范围}

在依赖中可设置scope标签代表依赖的范围,可选参数有compile、provided、runtime、test,默认是compile。

<dependency>
    <groupId>io.github.oliverliy</groupId>
    <artifactId>fast-sso-client</artifactId>
    <version>0.0.2</version>
    <scope>compile</scope></dependency>

当scope为compile时,项目代码(main文件夹范围内)、测试代码(test文件夹范围内)和package打包指令下这个依赖都有效,绝大部分的Jar包都是compile。

当scope为test时,只有测试代码范围内是有效的,最常见的就是junit包,只会在测试代码里使用就可以将scope定为test。

当scope为provided时,表示在项目代码范围和测试代码范围内有效,但是不会被打包,常见的是servlet-api这个依赖,原因是如果将servlet-api打入jar包,就会和一些web容器里的servlet依赖冲突。

当scope为runtime时,主会在打包时生效,最常见的就是jdbc的驱动依赖,我们写jdbc代码时,驱动都是用全限定名的字符串指定的,因此在项目代码中根本就不会用到,只要在打包时把这个jar包打进去就行。

# (四)Maven的生命周期 {#四-maven的生命周期}

maven的生命周期很长,但是我们只需要关注最常用的那些就可以了,在IDEA的maven插件中,就可以看到常用的生命周期:

从上往下代表了Maven的生命周期,当执行某个命令时,它往前的生命周期命令都会被执行,比如执行compile,那么会依次执行clean、validate、compile。

有的时候我们在打包时希望可以跳过测试,那么可以通过命令

mvn install -D skipTests

或者在IDEA中直接通过闪电符号快速跳过

其中比较常用的几个命令:clean会清除掉前一次的打包记录。compile会编译项目的源代码、package会将编译后的代码打包成文件,比如war包、jar包。install会安装项目包到本地仓库,这样其他项目就可以使用该项目包。deploy可以将项目包发送到远程仓库中。

# (五)Maven中的插件 {#五-maven中的插件}

插件和生命周期的每个阶段绑定,maven中的每个生命周期上都绑定有预设的功能,通过插件可以实现更多的自定义功能。比较常用的是打包插件,比如我现在想要打一个源码包,就可以在maven的官网找到对应的插件:

然后放到pom文件中去:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-source-plugin</artifactId>
            <version>3.2.0</version>
            <executions>
                <execution>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                    <phase>test</phase>
                </execution>
            </executions>
        </plugin>
    </plugins></build>

其中groupId、artifactId、version就不用介绍了,executions表示插件执行的参数,其中goals对应官网中的goals

每个插件都有自己的goals,比如这个打源码包的插件,当选择jar时,就表示将源码文件打包到一个jar文件中去。 phase表示在哪个生命周期执行,选择test就表示在test这个生命周期内执行。

# (六)Maven中的模块聚合 {#六-maven中的模块聚合}

为了更方便地管理整个项目的版本,往往会在父项目中将各个模块都会用到的依赖控制起来,防止每个模块用不同版本的依赖包,这个时候就需要用到<dependencyManagement>。 首先在父工程中定义依赖包:

<dependencyManagement>
    <dependencies>
        <artifactId></artifactId>
        <groupId></groupId>
        <version></version>
    </dependencies></dependencyManagement>

接着在每个子项目上用parent标签指出依赖的父工程是谁:

<parent>
    <artifactId></artifactId>
    <groupId></groupId>
    <version></version></parent>

这样子工程就可以使用父工程里引入的依赖包了。

同样的方式可以管理插件,pluginManagement起到了和dependencyManagement一样的能力。

# (七)Maven的版本管理 {#七-maven的版本管理}

在依赖包中,经常可以看到有些版本会带上SNAPSHOT,有些就不会带。这就是Maven的不同版本所附有的标识。

SNAPSHOT代表快照版本,也就是测试阶段版本,这个版本会随着开发进度不断更新。

RELEASE是发布版本,当项目开发达到某个相对稳定的阶段时,就可以对外发布相对稳定的版本,这种版本就是发布版本。

但是在maven库中,也能发现有些开源jar包命名并非是SNAPSHOT和RELEASE,这些还是按照每个企业自己的定义即可。

赞(4)
未经允许不得转载:工具盒子 » 你真的了解Maven吗?