Maven仓库与依赖管理

Maven仓库与依赖管理

仓库

1.概念

在Maven世界中,任何一个依赖、插件或者项目构建的输出,都可以称为构件。而仓库指的是存储所有Maven项目共享构件的位置。
项目构建的输出,把某项目通过安装(mvn install)生成构件,部署(或上传)到仓库中,供其它项目使用

2、分类

在Maven中,仓库主要分为两类:本地仓库和远程仓库
如果系统在本地仓库找不到需要的构件(jar包),则系统会在远程仓库查找。如果在远程仓库找不到构件,则系统会报错。

远程仓库

远程仓库又分为:中央仓库、私服和其它公共库。镜像仓库和中央仓库具有一样的功能,它解决外国网站访问不了的问题。可以通过settings.xml文件来配置镜像仓库。

<mirror>
  <id>nexus-aliyun</id>
  <mirrorOf>center</mirrorOf>
  <name>Nexus aliyun.</name>

  <url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
  • id:镜像的唯一标识符(可自定义)
  • name:镜像的名称(可自定义)
  • url:镜像的地址
  • mirrorOf:需要重定向的仓库
    将需要重定向的请求都会重定向到阿里巴巴的仓库中,也可以配置成*号,表示所有请求都重定向到阿里巴巴的仓库中。

Maven会在每台机器上创建一个本地仓库,用于把本机所有maven项目依赖的jar包统一管理起来,而且这些jar包用“坐标”来唯一标识。

<localRepository>
    E:/Java/local-repository
</localRepository>

POM.xml

1、概念

Project Object Model(POM):项目对象模型。和 POM 类似的有DOM(Document Object Model),文档对象模型。它们都是模型化思想的具体体现。

2、模型化思想

POM 表示将工程抽象为一个模型,再用程序中的对象来描述这个模型。这样我们就可以用程序来管理项目了。我们在开发过程中,最基本的做法就是将现实生活中的事物抽象为模型,然后封装模型相关的数据作为一个对象,这样就可以在程序中计算与现实事物相关的数据。

3、对应的配置文件

POM 理念集中体现在 Maven 工程根目录下 pom.xml 这个配置文件中。所以这个 pom.xml 配置文件就是 Maven 工程的核心配置文件。其实学习 Maven 就是学这个文件怎么配置,各个配置有什么用。
在Maven中,有两个重要的配置文件,分别为:

  • settings.xml:全局配置文件,作用于所有的项目
  • pom.xml:项目级别的配置文件(位于项目根目录),作用于当前的项目

POM常见配置

1、 modelVersion

<modelVersion>4.0.0</modelVersion>

2、当前项目的GAV坐标

每创建一个Maven项目,都应该为其制定一个坐标,那么在其他项目中需要使用到当前项目时,就可以通过坐标进行依赖。

<!-- 组织名称 -->
<groupId>edu.nf</groupId>
<!-- 项目名称 -->
<artifactId>mavendemo</artifactId>
<!-- 版本号 -->
<version>1.0-SNAPSHOT</version>

3、打包方式

指定项目的包的方式。默认是jar,可以为war、zip、pom。

  • jar:Java工程
  • war:WEB工程
  • pom:一般用于定义父工程,表示对各个子工程进行管理的工程
<packaging>war</packaging>

4、属性配置

1)内置属性

<properties>
  <!-- 设置项目的编码 -->
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <!-- 设置java的版本为1.8-->
  <java.version>1.8</java.version>
  <!-- 源码编译的版本为1.8-->
  <maven.compiler.source>1.8</maven.compiler.source>
  <!-- 目标字节码的版本为1.8-->
  <maven.compiler.target>1.8</maven.compiler.target>
  <!-- 指定编译器版本为1.8-->
  <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>

  <!-- 配置控制台输出参数的编码格式 -->
  <argLine>-Dfile.encoding=UTF-8</argLine>
</properties>

属性名称固定,用于设置Maven的基本配置及相关插件属性的设置。

2)自定义属性

<properties>
  <!-- 第三方库的版本号管理 -->
  <!-- junit单元测试 -->
  <junit.version>4.12</junit.version>
  <!-- mysql数据库驱动-->
  <mysql.driver.verison>5.1.47</mysql.driver.verison>
</properties>

用户自定义,如:可用于项目统一版本号的设置。

5、依赖配置

项目所需要的第三方jar文件的依赖配置,配置依赖通常只要填写第三方库的GAV坐标以及作用域。
根元素project下的dependencies可以包含一个或多个dependency元素,以声明一个或多个依赖。每个依赖可以包含的元素有:

  • groupId、artifactIdversion:依赖的基本坐标,坐标三元素(GAV)。对任何一个依赖来说,基本坐标是最重要的,Maven根据坐标才能找到需要的依赖。
  • type:依赖的类型,对应于项目定义的packaging,大部分情况下不需要定义,使用默认值jar。
  • scope:依赖的范围。
  • optional:标记依赖是否可选。
  • exclusions:用来排除传递性依赖。

https://mvnrepository.com/

<dependencies>
  ...
  <!-- mysql驱动依赖-->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
    <!-- 版本号也可以使用${}引用properties中配置的标签名称 -->
    <!-- <version>${mysql.driver.verion}</version> -->

    <type></type>
    <scope>依赖范围</scope>
    <!-- 设置依赖是否可选-->
    <optional>true|false</optional>
    <!--排除依赖传递列表-->
    <exclusions>
      <exclusion>
        <groupId>xxx</groupId>
        <artifactId>xxx</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
  ...
</dependencies>

1)依赖范围

用来控制依赖与三种classpath(编译,测试,运行)的关系。maven提供的三种classpath:

  • 编译
  • 测试
  • 运行
<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.10</version>
    <scope>test</scope> 
  </dependency>
</dependencies>

2)依赖范围的分类

1)compile:编译依赖范围,编译、测试、运行都有效。如果没有指定,则默认使用该依赖范围
2)test:测试依赖范围(不会依赖传递),只在测试时有效
3)provided:已提供依赖范围,在编译和测试时有效
4)runtime:运行时依赖范围,在测试和运行时有效
5)system:系统依赖范围,与本机系统相关联,可移植性差
6)import:导入依赖范围,它只使用在dependencyManagement中,表示从其它的pom中导入dependecy的配置
file

3)依赖管理

通常用于父模块的定义,子模块继承使用

<dependencyManagement>
  <dependencies>
    <denpendency></denpendency>
  </dependencies>
</dependencyManagement>

五、依赖管理

通过前面的学习,我们知道Maven对于项目中的依赖,会从本地仓库或远程仓库中查找。除此之外,Maven在的依赖的过程中还包括依赖的传递、依赖的优先级别、排除依赖、可选依赖、及依赖范围等特点,下面将分别进行讲解和学习。

1、 依赖传递性

Maven的依赖是具有传递性的。举个例子,项目中只配置依赖了A,而A又依赖了B,B又依赖了C,那么项目就间接的依赖了B和C,这就是依赖传递性。

A->B->C

注意:

  • 依赖范围为compile时,具有依赖传递性
  • 如果依赖范围为test或provided时,不具有依赖传递性

    2、依赖传递的优先级别

    上面我们知道依赖具有传递性,接下来我们看看下面的情况。

A->B->C->X(1.0)
A->D->X(2.0)

上面A依赖B,B依赖C,C依赖X,同时A又依赖了D,D也依赖了X。如果两个X的版本(version)不一样,一个是1.0和一个2.0,此时Maven会选择哪一个呢?由于只能引入一个版本。因此Maven优先选择最短路径的依赖,也就是A->D->X(2.0)。
另外一种情况就是如果路径长度是一样,像以下的情况。

A->B->C->X(1.0)
A->D->E->X(2.0)

此时Maven会按照配置顺序选择第一个,也就是A->B->C->X(1.0)。因此我们得出一个结论,当出现依赖同一个项目时,优先选择最短路径的依赖,如果路径长度相同,则按照配置顺序选择最前的进行依赖。

3、依赖排除

Maven 中的依赖关系是有传递性的。例如:项目B依赖项目C(B —> C),如果有一个项目A依赖项目B(A —> B)的话,那么项目A也会依赖项目C(A —> C)。虽然,这种依赖的自动传递性给我们维护项目的必要依赖关系带来了极大地方便,但在某些情况下,需要在项目A中排除对项目C的依赖时,这时又该怎么做呢?Maven 为我们提供了两种解决方案,分别是可选依赖和依赖排除。下面先看看依赖排除的使用。
例如在项目A的pom文件中依赖了项目B。
pom.xml示例:

<!-- 在project-A中依赖了project-B -->
<dependencies>
  <dependency>
    <groudId>edu.nf</groudId>
    <artifactId>project-B</artifactId>
    <version>1.0-SNAPSHOT</version>
  </dependency>
</dependencies>

接着项目B的pom文件中依赖了项目C。
pom.xml示例:

<!-- 在project-B中依赖了project-C -->
<dependencies>
  <dependency>
    <groudId>edu.nf</groudId>
    <artifactId>project-C</artifactId>
    <version>1.0-SNAPSHOT</version>
  </dependency>
</dependencies>

此时项目A会间接依赖项目C(传递依赖),如果想要在A中排除对C的依赖,只需要在A中配置exclusions即可。(注:排除时不需要指定version)
pom.xml示例:

<!-- 在project-A中依赖了project-B -->
<dependencies>
  <dependency>
    <groudId>edu.nf</groudId>
    <artifactId>project-B</artifactId>
    <version>1.0-SNAPSHOT</version>
    <exclusions>
      <!-- 排除对project-C的依赖 -->
      <exclusion>
        <groupId>edu.nf</groupId>
        <artifactId>project-C</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
</dependencies>

4、可选依赖

上面使用排除的方式排除了A对C的依赖,还可以使用另一种方式达到同样效果,就是可选依赖。可选依赖可以在B依赖C的时候设置optional为true。
pom.xml示例:

<!-- 在project-B中依赖了project-C -->
<dependencies>
  <dependency>
    <groudId>edu.nf</groudId>
    <artifactId>project-C</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!-- 将project-C设置为可选依赖 -->
    <optional>true</optional>
  </dependency>
</dependencies>

那么当A依赖B时,就不会间接依赖C。
pom.xml示例:

<!-- 在project-A中依赖了project-B,但不会间接依赖peoject-C -->
<dependencies>
  <dependency>
    <groudId>edu.nf</groudId>
    <artifactId>project-B</artifactId>
    <version>1.0-SNAPSHOT</version>
  </dependency>
</dependencies>

如果A想再次用到C的话,那么可以在项目A对C重新进行依赖。
pom.xml示例:

<!-- 在project-A中依赖了project-B -->
<dependencies>
  <dependency>
    <groudId>edu.nf</groudId>
    <artifactId>project-B</artifactId>
    <version>1.0-SNAPSHOT</version>
  </dependency>
  <!-- 重新依赖project-C -->
  <dependency>
    <groudId>edu.nf</groudId>
    <artifactId>project-C</artifactId>
    <version>1.0-SNAPSHOT</version>
  </dependency>
</dependencies>

5、依赖范围

依赖范围表示依赖的项目在哪些情况下需要存在,由依赖配置中的决定。
pom.xml示例:

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <!-- 指定依赖的作用范围 -->
  <scope>provided</scope>
</dependency>

Maven的依赖范围总共分为5种,compile (编译)、test (测试)、runtime (运行时)、provided(提供者)、system(系统)。如果不指定,则默认为compile。

范围 说明
compile 在编译,测试,运行时都需要
test 测试时需要。编译和运行不需要。如Junit
runtime 测试和运行时需要。编译不需要。如JDBC驱动包
provided 编译和测试时需要。运行时不需要,由运行环境提供。如servlet-api
system 本地依赖,不在maven中央仓库