Myike 的个人博客 Myike 的个人博客

记录精彩的程序人生

目录
maven之坐标和依赖
/  

maven之坐标和依赖

坐标 :

 Maven作为一款优秀的项目构建工具,当然也不仅仅只有构建,它还是一款依赖管理工具以及项目信息管理工具;正是有了maven的存在,Java开发中那些繁琐重复的导包行为彻底与我们告别,这无疑解放了很大一部分的劳动力。吹嘘到此结束,下面开始介绍maven的坐标与依赖:

关于坐标,记忆里平面几何数学题便涌上心头;几何平面中要表达某个图案所在的位置,找一个相对原点,建立X轴、Y轴。。。。

那么这个图案的位置已然确定;这当中的应用不乏网上购物时的收货地址,它代表的是具体的一个位置,方便寻找而已。maven中的坐标呢,当然也是基于这点;要知道maven中央仓库中的代码构件数量是十分巨大的,坐标就对应着每一款构件的具体位置。

Maven坐标代表的是规范秩序,任何构件都必须定义自己的坐标;而一组坐标是通过一些元素定义的,其中有groupId、artifactId、version、packaging、classifier。先看一个实例:

top.tzwyun.shop

shop-server

1.0.0

jar

这是我自己一个maven项目的坐标定义,现在详细解释一下各个坐标元素:

groupId:表示当前Maven项目所在的实际项目路径,当然这一路径下有可能多个模块;通常groupId的命名方式与域名反向一一对应,如我的域名为www.tzwyun.top。



artifactId:该元素定义的是实际项目路径下的具体的一个maven项目(模块),与groupId组合起来就可以很方便地定位到该项目的详细路径;命名推荐使用实际项目名称作为artifactId的前缀,如本例中的shop-server。



version:从字面理解就能知道,该字段定义的是当前maven项目所处的版本。



packaging:该元素定义Maven项目的打包方式,对于不同的打包方式所生成的构件的文件扩展名是想对应的;如上例打包后生成的文件名为shop-server-1.0.0.jar。



classifier:该元素用来帮助定义构建输出的一些附属构件,什么是附属构件呢?附属构件定义就是:该项目可能还会通过使用一些插件生成shop-server-1.0.1-sources.jar这样一些附属构件,就如shop-server-1.0.1-sources.jar包含的是项目的源代码。需要注意的是,附属构件与主构件(即本项目)想对应,classifier不能直接被定义,因为附属构件不是项目直接默认生成的,而是由附加的插件帮助生成的。

依赖:

前人写下的优秀开源框架你想拿来用,在maven中只需加入相应框架依赖即可;依赖的导入依然是有相应的配置规则,如下例:
    <dependencies>

   <dependency>

       <groupId>junit</groupId>

       <artifactId>junit</artifactId>

       <version>...</version>

       <type>...</type>

       <optional>...</optional>

       <scope>test</scope>

       <exclusions>

            <exclusion>

            ....

            </exclusion>

       </exclusions>

    </dependency>

    .....

</dependencies>

Maven项目的pom.xml文件的根元素project下的dependencies可以包含一个或多个dependency元素,这个dependency元素就是依赖的对象项目。而每个dependency可以包含的元素有:

gourpId、artifactId、version:依赖的项目也是一个maven项目,所以这三个元素对于任何一个依赖来说都是最重要的,根据这三个信息,maven能找到所需的依赖。

type:标识依赖的类型,对应的是项目坐标中的packaging元素,缺省值为jar

scope:表示依赖的范围,针对maven不同生命周期是否需要该依赖的标识,下面会详解

optional:标记该依赖是否是可选配置,下面详解

exclusions:用以排除不需要的项目依赖

何谓scope依赖的范围?就如上例中的junit框架,Maven在执行测试运行时才会引入该依赖;在编译和运行时则不会引入该依赖,依赖范围就是用来控制依赖与三种运行期间(也叫三种classpath)的关系。scope可选的集中依赖范围有:

compile:编译依赖范围;也是scope的缺省值;使用此范围,对编译、测试、运行三种classpath都有效。



test:测试依赖范围;标识此依赖只对测试classpath有效



provided:已提供依赖范围,对于编译和测试有效,运行时无效,比如servlet-api,编译和测试时需要引入,但是运行时,由于项目容器已提供,就不要重复引入该依赖。



runtime:运行时范围,只对运行classpath有效。



system:系统依赖范围,在三种classpath都有效,但必须通过systemPath元素显示地制定依赖文件的路径,通俗点说就是导入指定位置文件,不通过maven仓库解析。此依赖范围往往与本机系统绑定,可能造成构建不可移植,谨慎使用!systemPath可以引用环境变量,如:
<groupId>...</groupId>

<artifactId>...</artifactId>

<version>...</version>

<scope>system</scope>

<systemPath>${JAVA_HOME}/lib/rt.jar</systemPath>
import(Maven 2.0.9及以上):导入依赖范围。该依赖范围不会对三种classpath产生实际的影响,该范围的依赖通常指向一个POM,作用是将目标POM中的dependencyManagement配置导入并合并到当前POM的dependencyManagement元素中,简化了子模块重复配置依赖的pom.xml文件。

说完了依赖的范围,现在来说说传递性依赖;什么是传递性依赖?在日常开发中,当前maven项目依赖了spring-core,而spring-core又依赖了dom4j,那么dom4j便会自动被依赖于当前项目;这就是传递性依赖。假设A依赖于B,B又依赖于C,那么A对B是第一直接依赖,B对C是第二直接依赖,A对C是传递性依赖。第一直接依赖的范围和第二直接依赖的范围则决定了第二直接依赖范围,下图为传递性依赖的范围:

总结上图的依赖关系可得出如下规律:

当第二直接依赖的范围是compile时,传递性依赖的范围与第一直接依赖范围一致;

当第二直接依赖的范围是test时,依赖不会传递;

当第二直接依赖的范围是provided时,只传递第一直接依赖也为provided的依赖;

当第二直接依赖的范围是runtime时,除compile外都与第一直接依赖范围一致,当为compile时,传递性依赖的范围为runtime。

看完了上面多级依赖的例子,大家可能会想到一个问题;假如有这样的依赖关系:A-B-C-X(1.0)、A-D-X(2.0),那么X是A的传递性依赖,但是两条路径依赖的X的版本却不同,那么哪个版本会被maven解析呢?这就要说到maven的依赖调解了。

那么依赖调解的第一原则是:路径最近者优先。在上面的例子中,版本1.0的路径为3大于版本2.0的依赖路径;因此maven会解析X(2.0)依赖。当然依赖调解不能解决所有问题,比如:A-B-Y(1.0)、A-C-Y(2.0),可以看到按照第一原则两个依赖的路径长度是相等的,所以无法确定使用哪个依赖。在maven 2.0.8及以前的版本中是不确定的,但是从maven 2.0.9之后,maven定义了依赖调解的第二原则:第一声明者优先。在依赖路径相等的情况下,在pom.xml文件中声明的顺序决定了哪个版本会被解析使用。

optional

接下来说一说可选依赖配置,顾名思义便是可以选择的依赖构件。为什么会有可选依赖这一特性呢?有这样一种需求,项目A依赖X或Y当中一个,X和Y不能同时依赖,因此可以将该依赖配置成可选的依赖。比如一个持久层隔离工具包,它支持多种数据库;包括mysql、oracle等,在构建这个工具包时,需要这两种数据库的依赖,但是在具体使用该工具包时,只会依赖其中一种数据库。当然可选依赖是不会传递的,该特性不推荐使用。

Optional配置示例


exclusions

因为传递性依赖会给项目隐式地引入很多依赖,但是有些依赖可能会与显示地依赖构件发生冲突,从而导致项目的运行出错;或者你想替换隐式引入的某个依赖,则可以选择在该属性中排除相应的依赖,在pom.xml文件中引入所需要的构件依赖,示例如下:

exclusions配置示例


以上就是maven的坐标和依赖相关知识点


标题:maven之坐标和依赖
作者:Myike
地址:https://tzwyun.top/articles/2020/04/11/1586590105073.html