乐趣区

关于java:五分钟快速掌握Maven的核心概念

关注“Java 后端技术全栈”

回复“面试”获取全套面试材料

前两天在一个技术群,有人还在问 maven 中 groupId、artifactId、version 这些关键字的含意是什么,于是,我感觉还是很有必要来聊聊 Maven 中的这些外围概念。

胜利不是未来才有的,而是从决定去做的那一刻起,继续累积而成。

明天咱们来学习 Maven 中的外围概念。理解了这些外围概念后,咱们前面就能够更深层次的学习和应用 Maven。

坐标

坐标的概念

来自百度百科

可能确定一个点在空间的地位的一个或一组数,叫做这个点的坐标。通常由这个点到垂直相交的若干条固定的直线的间隔来示意。这些直线叫做坐标轴。坐标轴的数目在立体上为 2(x,y),在空间里为 3(x,y,z)。

其实就是能够标识立体中或空间里惟一的一个点。

Maven 中的坐标

Maven 其中一个外围的作用就是治理我的项目的依赖,引入咱们所需的各种 jar 包等。为了能自动化的解析任何一个 Java 构件,Maven 必须将这些 Jar 包或者其余资源进行惟一标识,这是治理我的项目的依赖的根底,也就是咱们要说的坐标。包含咱们本人开发的我的项目,也是要通过坐标进行惟一标识的,这样能力才其它我的项目中进行依赖援用。

案例

依赖时候: 比方上面咱们依赖 junit 的 jar 包。

<!-- pom.xml 中 -->
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>3.8.1</version>
  <scope>test</scope>
</dependency>

我的项目中定义咱们的我的项目将打成 jar 或者 war 包。

<?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.tian</groupId>
        <artifactId>maven-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
        <!-- 默认是 jar -->
        <packaging>jar</packaging>
</project>

最初打进去的 jar 或 war 的模式的模式:

artifactid-version.jar
artifactid-version.war

packaging 标签默认是 jar,所以通常咱们在没有指定打成 jar 包还是 war 的时候,最终打成的就是 jar 包。

Maven 坐标的组成

「groupId」组织标识(包名)。定义以后 Maven 我的项目附属的理论我的项目。首先,Maven 我的项目和理论我的项目不肯定是一对一的关系。比方 SpringFrameWork 这一理论我的项目,其对应的 Maven 我的项目会有很多,如 spring-core,spring-context 等。这是因为 Maven 中模块的概念,因而,一个理论我的项目往往会被划分成很多模块。其次,groupId 不应该对应我的项目附属的组织或公司。起因很简略,一个组织下会有很多理论我的项目,如果 groupId 只定义到组织级别,而前面咱们会看到,artifactId 只能定义 Maven 我的项目(模块),那么理论我的项目这个档次将难以定义。最初,groupId 的示意形式与 Java 包名的表达方式相似,通常与域名反向一一对应。上例中,groupId 为 junit,是不是感觉很非凡,这样也是能够的,因为全世界就这么个 junit,它也没有很多分支。

「artifactId」项目名称。该元素定义以后理论我的项目中的一个 Maven 我的项目(模块),举荐的做法是应用理论项目名称作为 artifactId 的前缀。比方上例中的 junit,junit 就是理论的项目名称,不便而且直观。在默认状况下,maven 生成的构件,会以 artifactId 作为文件头,如 junit-3.8.1.jar,应用理论项目名称作为前缀,就能不便的从本地仓库找到某个我的项目的构件。

「version」我的项目的以后版本或者咱们要依赖 jar 的版本。该元素定义了应用构件的版本,如上例中 junit 的版本是 3.8.1,你也能够改为 4.0 示意应用 4.0 版本的 junit。

「packaging」我的项目的打包形式,最为常见的 jar 和 war 两种,默认是 jar。定义 Maven 我的项目打包的形式,应用构件的什么包。首先,打包形式通常与所生成构件的文件扩展名对应,如上例中没有 packaging,则默认为 jar 包,最终的文件名为 junit-3.8.1.jar。也能够打包成 war 等。

「classifier」 该元素用来帮忙定义构建输入的一些附件。从属构件与主构件对应,如上例中的主构件为 junit-3.8.1.jar, 该我的项目可能还会通过一些插件生成如 junit-3.8.1-javadoc.jar,junit-3.8.1-sources.jar, 这样从属构件也就领有了本人惟一的坐标。

上述 5 个元素中,groupId、artifactId、version 是必须定义的,packaging 是可选的(默认为 jar),而 classfier 是不能间接定义的,须要联合插件应用。

Maven 为什么应用坐标呢?

  • Maven 世界里领有大量构建,咱们须要找一个用来惟一标识一个构建的对立标准。
  • 领有了对立标准,就能够把查找工作交给机器。

maven 依赖治理

依赖

依赖通常体现为:我须要你的货色,就像情侣之间相互依赖,夫妻之间相互依赖,人依赖于水,人依赖于食粮等。

在 Maven 中则体现为:我的项目中用到 b.jar 包的每个类,此时的我的项目就依赖 b.jar。

简单点关系就是多层依赖:a.jar 包依赖 b.jar 包,还有可能 b.jar 包依赖 c.jar。这种景象也能够称之为依赖传递性。

咱们的我的项目间接性的依赖了 b.jar。

依赖配置

Maven 中依赖配置案例如下:

<!-- 增加依赖配置 -->
<dependencies>
  <!-- 我的项目要应用到 junit 的 jar 包,所以在这里增加 junit 的 jar 包的依赖 -->
  <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.9</version>
      <scope>test</scope>
  </dependency>
  <!-- 我的项目要应用到 Hello 的 jar 包,所以在这里增加 Hello 的 jar 包的依赖 -->
  <dependency>
      <groupId>com.tian.maven</groupId>
      <artifactId>user-service</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <scope>compile</scope><!-- 依赖范畴 -->
  </dependency>
</dependencies>

依赖范畴

所谓的依赖范畴就是指咱们在什么须要依赖的 jar。有的是在编译的时候就须要,有的是测试的时候须要等。

依赖范畴 scope 有以下 6 种:

「compile」 默认编译依赖范畴。对于编译,测试,运行三种 classpath 都无效。即在编译、测试和运行的时候都要应用该依赖 jar 包;

「test」测试依赖范畴。只对于测试 classpath 无效。而在编译和运行我的项目时无奈应用此类依赖,典型的是 JUnit,它只用于编译测试代码和运行测试代码的时候才须要;

「provided」已提供依赖范畴。对于编译,测试的 classpath 都无效,但对于运行有效。因为由容器曾经提供,例如 servlet-api.jar,这个在编译和测试的时候须要用到,然而在运行的时候,web 容器曾经提供了,就不须要 maven 帮忙引入了。

「runtime」运行时依赖范畴,应用此依赖范畴的 maven 依赖,对于编译测试、运行测试和运行我的项目的 classpath 无效,但在编译主代码时有效,比方 jdbc 驱动实现,运行的时候才须要具体的 jdbc 驱动实现。

「system」零碎依赖范畴,应用 system 范畴的依赖时必须通过 systemPath 元素显示地指定依赖文件的门路,不依赖 Maven 仓库解析,所以可能会造成建构的不可移植(即就是在你的电脑上可能没问题,然而到他人电脑上那就说不清楚了),有点相似 provided,留神这个 system 审慎应用。

<systemPath>${java.home}/lib/rt.jar</systemPath>

「import」仅 pom 在本节中的类型依赖项上反对此作用域。它批示依赖关系将被指定的 pom 局部中的无效依赖关系列表替换。因为已替换它们,因而范畴为的依赖项 import 实际上不会参加限度依赖项的可传递性,在 springboot 和 springcloud 中用到的比拟多。

以上六种范畴中,罕用的有 compile、test、runtime、provided。

依赖范畴不仅能够管制与三种 classpath 的关系,还对传递性依赖产生影响,依赖关系图如下:

「留神」预期这应该是运行时范畴,因而必须明确列出所有编译依赖项。然而,如果您依赖的库从另一个库扩大了一个类,则两者都必须在编译时可用。因而,即便编译工夫相关性是可传递的,它们仍保留为编译范畴。

Maven 仓库治理

Maven 仓库

用来对立存储所有 Maven 共享构建的地位,说白了就是用来寄存 jar 包的,咱们本地每次编译的时候没有对应 jar 包是编译通不过的,咱们一个我的项目中是须要很多 jar 的依赖的,这时候就晓得仓库的重要性了。

Maven 仓库布局

依据 Maven 坐标定义每个构建在仓库中惟一存储门路,大抵为:

groupId/artifactId/version/artifactId-version.packaging

本地仓库

在上一篇文章中,每个用户只有一个本地仓库,默认是在~/.m2/repository/,~ 代表的是用户目录。为了便于管理,个别都会本人搞一目录,专门用来存储本地仓库内容。这样咱们开发的时候,依赖那个 jar 就间接去咱们的本地仓库 repository 中去查找,如果没有,咱们会从地方仓库中拉取。

地方仓库

基本上保留了对外开发的所有 jar 包,Maven 默认的近程仓库,(外国网站)URL 地址:http://search.maven.org/。还有比方阿里的仓库,咱们在开发的时候,因为网络起因,很多人都喜爱应用阿里的这个仓库:http://maven.aliyun.com。

这时候咱们本地仓库和地方仓库的关系:

私服

大部分公司都会搭建私服,私服就是一种非凡的近程仓库,它是架设在局域网内的仓库。比方公司搭建局域网,公司也搞个仓库,而后开发人员就间接应用公司搭建的私服就行了,这样大大减少了网络开销以及开发成本(有时候外网拜访很慢,会节约大家开发工夫的)。

这样开发人员每次须要每个 jar 包就间接从公司的私服里拉取,不须要应用外网去地方仓库里拉取了。总之节约工夫和节约网络开始。并且有些企业还是不给外网的,这时候你就晓得这个私服的重要性了。

减少了私服后,本地仓库 + 私服 + 地方仓库的关系图:

面试中也频繁被问:本地仓库、私服以及地方仓库是什么关系?

Maven 生命周期

Maven 的 生命周期:从咱们的我的项目构建,始终到我的项目公布的这个过程。

每个阶段的阐明:

为了实现 default 生命周期,这些阶段 (包含其余未在下面列举的生命周期阶段) 将被按程序地执行。

Maven 有以下三个规范的生命周期:

  • Clean Lifecycle 在进行真正的构建之前进行一些清理工作。
  • Default Lifecycle 构建的外围局部,编译,测试,打包,部署等等。
  • Site Lifecycle 生成我的项目报告,站点,公布站点。

这三个规范它们是互相独立的,你能够仅仅调用 clean 来清理工作目录,仅仅调用 site 来生成站点。当然你也能够间接运行 mvn clean install site 运行所有这三套生命周期。

运行任何一个阶段的时候,它后面的所有阶段都会被运行,这也就是为什么咱们运行 mvn install 的时候,代码会被编译,测试,打包。此外,Maven 的插件机制是齐全依赖 Maven 的生命周期的,因而了解生命周期至关重要。

Maven 插件

Maven 是不做具体事件的,只是规定了生命周期的各个阶段和步骤,由集成到 Maven 中的插件实现。

  1. Maven 的外围仅仅定义了形象的生命周期,具体的工作都是交由插件实现的。
  2. 每个插件都能实现多个性能,每个性能就是一个插件指标。
  3. Maven 的生命周期与插件指标互相绑定,以实现某个具体的构建工作,例如 compile 就是插件 maven-compiler-plugin 的一个插件指标。

对于插件,这里就说个大略,后续会出一篇文章专门来说 Maven 插件。

排除不须要依赖

<dependency>
    <groupId>com.tian.maven</groupId>
    <artifactId>my-maven</artifactId>
    <version>1.0.0</version>
    <exclusions>
        <exclusion>
            <groupId>com.tian.maven</groupId>
            <artifactId>your-maven</artifactId>
        </exclusion>
    </exclusions>
</dependency>

下面应用应用 exclusions 元素排除了 my-maven->your-maven 依赖的传递,也就是 my-maven->your-maven 不会被传递到以后我的项目中。

exclusions 中能够有多个 exclusion 元素,能够排除一个或者多个依赖的传递,申明 exclusion 时只须要写上 groupId、artifactId 就能够了,version 能够省略。

总结

本文讲述 Maven 坐标,Maven 依赖治理、Maven 仓库治理、Maven 生命周期以及简略介绍了 Maven 插件。有了这些概念作为铺垫,咱们就能够更深层次去领会,为什么咱们在工作室这么用的。

「只有路是对的,就不怕路远。」

举荐浏览

面试官系列:说说 Integer 缓存范畴

面试官:说说你对序列化的了解

搞定这 24 道 JVM 面试题,要价 30k 都有底气~

退出移动版