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
导入依赖范围,待补充
依赖范围 | 对于编译有效 | 对于测试有效 | 对于运行时有效 | 例子 |
---|---|---|---|---|
compile | Y | Y | Y | spring-core |
test | N | Y | N | Junit |
runtime | N | Y | Y | jdbc |
provided | Y | Y | N | servlet-api |
system | Y | Y | N | oracle??? |
4、传递行依赖
不同的依赖范围由不同的传递行为,这些传递行为影响了实际项目中使用的依赖。
第一直接依赖 | compile | test | provided | runtime |
---|---|---|---|---|
compile | compile | runtime | ||
test | test | test | ||
provided | provided | provided | provided | |
runtime | runtime | runtime |
举例
- 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的依赖,来控制版本。