Maven系列-坐标和依赖
seefly
seefly
发布于 2020-07-07 / 41 阅读 / 0 评论 / 0 点赞

Maven系列-坐标和依赖

Maven

1、软件目录

  • bin

    包含了mavn运行脚本

  • boot

    只有一个plexus-classworlds-xx.jar是一个类加载器框架。相对于java类加载器,他提供了更加丰富的语法方便配置。

  • conf

    包含setting.xml配置文件,这是全局配置文件,在~/.,2/setting下是个人配置文件

  • lib

    包含了maven运行时需要的java类库

2、maven坐标

  • groupId

    定义当前maven项目隶属的实际项目,例如com.alibaba.cloud,其中com.alibaba是一个组织,而cloud则代表该组织下的其中一个项目,groupId不应该只对应到组织,应该包含实际的项目

  • artifactId

    定义实际项目中的一个maven项目或这模块,推荐的做法是使用项目名做前缀,比如groupId=com.alibaba.nacos,则其中的配置中心模块可以是artifactId=nacos-config;

    但如果这个项目只有这一个模块,那么我看到实际的pom里是取grouId中定义的项目名称,直接拿来做artifactId了,例如德鲁伊。

  • version

    定义了当前项目所处的版本,版本规范待补充

  • packaging

    定义当前maven项目的打包方式,默认为jar包方式,使用不同的打包方式,会影响构建的生命周期。


上面的几个参数除了packaging,其他的也可以用来引入依赖时的坐标定位。下面的只能用作引入依赖。

  • classifier

    定义附属构件,例如nexus-indexer-2.0.0-javadoc.jar,这个是主项目的java文档,通过指定classifier=javadoc,就能够在maven仓库中定位到这个附属构件了。

  • type

    对应引入依赖项目的packagin类型,默认为jar;

  • scope

    依赖范围

  • optional

    标记依赖是否可选

  • exclusions

    用来排除传递依赖

3、依赖范围

maven在编译项目主代码的时候需要一套classpath,在编译和执行测试的时候会使用另一套classpath,最后在项目实际运行的时候还会使用一套classpath;而依赖范围就是控制着三种classpath关系的;

  • compile

    编译依赖范围,如果没有指定则默认使用该依赖范围。使用该依赖范围的依赖,对于编译、测试、运行三种classpath都有效,例如spring-core;

  • test

    测试依赖范围,使用此依赖范围的依赖,对于编译主代码或者实际运行项目时时无法使用的,仅在编译测试代码和运行测试代码的时候有效;例如,junit

  • provided

    已提供依赖范围。使用此依赖范围的依赖,对于编译和测试有效,在运行时无效,且项目打包时该依赖不会被包含,并希望由项目运行环境提供。例如,servlet-api,编译和测试项目的时候需要改依赖,但在项目运行的时候由于容器环境已经提供,所以不会再当前项目中重复引入。也就是说可以预见性的知道我现在写的这个项目,它依赖的某个jar包会在将来会在实际运行的时候被提供。再例如我写一个公共组件包,它依赖rocketmq,并且知道使用这个公共组件的项目肯定会用到rocketmq,所以就可以定义这个rocketmq的范围为provided;所以在打包的时候这个rocketmq不被包含进去

  • runtime

    运行时依赖范围,使用此依赖范围的依赖,对于测试和运行有效。但在编译时无效;例如jdbc驱动,代码里不会用到它,但在运行时会动态加载驱动。打包时会被包含。

  • system

    系统依赖范围,使用此依赖范围必须指定systemPath元素,告诉依赖文件在当前系统的哪里能找到。由于和系统绑定,所以不可移植。

  • import

    导入依赖范围,待补充

依赖范围对于编译有效对于测试有效对于运行时有效例子
compileYYYspring-core
testNYNJunit
runtimeNYYjdbc
providedYYNservlet-api
systemYYNoracle???

4、传递行依赖

​ 不同的依赖范围由不同的传递行为,这些传递行为影响了实际项目中使用的依赖。

第一直接依赖compiletestprovidedruntime
compilecompileruntime
testtesttest
providedprovidedprovidedprovided
runtimeruntimeruntime

举例

  • A-->B(compile)-->C(compile) ==> A --> C(compile)
  • A -->B(test) --> C(compile) ==> A --> C(test)
  • A --> B(provided) --> C(runtime) ==> A -->C(provided)

总结一下,如果第二直接依赖是compile,那么它对于当前项目的范围和第一直接依赖相同;

5、依赖调解

由于依赖传递的机制,所以实际项目中可能会发生依赖冲突的问题,maven有两个原则来选择在冲突的时候使用哪个依赖。

  • 路径最近者优先原则

    如A --> B --> X(v1.0) 和 A --> C --> D --> X(v2.0),此时会选择B的X(v1.0)依赖;

  • 第一声明者优先原则

    在路径长度相同的时候,谁在POM中定义的位置靠前,就使用谁的依赖。

6、依赖排除

有时候在发生依赖冲突的时候,例如对于rockeMq版本问题,可以通过 <exclusion> 标签来排除,依赖B中对于C的依赖。又或者使用 路径最近者优先原则 直接在项目中直接定义对rockeMq的依赖,来控制版本。


评论