Maven
环境配置
- Maven 是一个基于 Java 的工具,所以要做的第一件事情就是安装 JDK
- Maven 自身安装需要大约 10 MB 空间。除此之外,额外的磁盘空间将用于你的本地 Maven 仓库。你本地仓库的大小取决于使用情况
坐标
- groupId:当前Maven项目隶属项目。
- Maven项目和实际项目不一定是一对一的关系(模块的原因)
- 不应该对应项目隶属的组织或公司(一个组织下会有多个实际项目)
- 表示方式与java包名方式类似,通常与域名反向一一对应
- artifactId:定义项目中实际的一个Maven项目(模块)
- 推荐使用项目实际项目名称作为artifactId的前缀
- version:Maven项目当前所处版本
- packaging:打包方式
- 打包方式通常与生成构建的文件拓展名对应
- 打包方式会影响到构建的生命周期
- 默认打包方式为jar
- classifier:定义输出的一些附属组件
- 附属组件与主构件对应,例如Java文档和源代码
groupId、artifactId、version必须定义,packaging可选,classifier不能直接定义
项目构建的文件名始于坐标相对应的,一般规则为artifactId-version[-classifier].packaging
依赖
- groupId、artifactId、version:依赖的基本坐标
- type:依赖类型,默认为jar
- scope:依赖范围
- optional:依赖是否可选
- exclusions:排除传递性依赖
依赖范围
Maven在编译、测试、运行(含打包)阶段中所需的依赖并不完全一致,依赖范围就是用来控制依赖与三种classpath(编译classpath、测试classpath、运行classpath)的关系。
范围 | classpath范围 | 例子 | 补充 |
---|---|---|---|
编译 compile |
编译、测试、运行 | spring-core | 默认依赖范围 |
供应 provided |
编译、测试 | servlet-api | 如果不显示指定该依赖范围,并且容器依赖的版本和maven依赖的版本不一致的话,可能会引起版本冲突,造成不良影响。 |
运行 runtime |
测试、运行 | JDBC驱动 | |
测试 test |
测试 | Junit | 编译主代码和运行项目时使无法使用此依赖 |
系统 system |
编译、测试 | 必须通过配置systemPath元素来显示指定依赖文件的路径,此类依赖不是由maven仓库解析的,而且往往与本机系统绑定,可能造成构件的不可移植,因此谨慎使用。systemPath可以引用环境变量 | |
导入 import |
不会对三种classpath产生影响,该依赖范围只能与dependencyManagement元素配合使用 将目标pom文件中dependencyManagement的配置导入合并到当前pom的dependencyManagement中。 |
可传递性依赖
Maven会解析各个直接依赖的POM,将那些必要的间接依赖,以传递性依赖的形式引入到当前的项目中
可传递性依赖和依赖范围
第一直接依赖 \ 第二直接依赖 | compile | test | provided | runtime |
---|---|---|---|---|
compile | compile | runtime | ||
test | test | test | ||
provided | provided | provided | provided | |
runtime | runtime | runtime |
依赖调节
- 路径最近者优先
- 第一声明者优先
可能导致问题:依赖冲突。依赖的版本和实际使用的版本不一致,常见的表现有NoSuchMethodError,ClassNotFoundException 等。
解决方法:依赖排除
可选依赖
元素为true,标识当前依赖为可选依赖,该依赖不会得到传递
理想情况下,是不应该使用可选依赖的,用可选依赖的某一个原因是某一个项目实现了多个特性,这违反了单一职责性原则
排除依赖
元素声明排除依赖,可以包含一个或多个元素,因此可以排除一个或多个传递性依赖。
**声明的时候只需要groupId和artifactId,而不需要version元素。**因为只需要groupId和artifactId就能唯一定位依赖图中的某个依赖,即Maven解析后的依赖中,不可能出现groupId和artifactId相同,而version不同的两个依赖。
归类依赖
原因:同一项目下不同依赖的版本相同,避免重复
- 使用properties元素定义Maven属性
- 使用Maven属性(${属性名})代替实际version值
优化依赖
- 已解析依赖(Resolved Dependency):Maven会自动解析所有项目的直接依赖和传递性依赖,并且根据规则正确判断每个依赖的范围,对于一些依赖冲突,也能进行调节,以确保任何一个构建只有唯一的版本在依赖中存在。最后得到的依赖称为已解析依赖。
查看命令:
mvn dependency:list
- 依赖树:将当前项目POM声明的依赖定义为顶层依赖,而这些依顶层依赖的依赖规则定义为第二层依赖,以此类推,有第三、第四层依赖。
查看命令:
mvn dependency:tree
- 解析依赖
查看命令:
mvn dependency:analyze
Used undeclared dependencies:项目中使用到,但没有显示声明的依赖。存在这潜在的危险,当直接依赖升级时,相关传递依赖的版本也可能发生变化,这种变化不易察觉,但是有可能导致当前项目出错
Unused declared dependencies:项目中未使用到,到显示声明的依赖。不能简单的直接删除,需要仔细分析,因为dependency:analyze只会分析编译主代码和测试代码需要用到的依赖,一些执行测试和运行时需要的依赖它就发现不了
排除依赖 VS 可选依赖
排除依赖和可选依赖都能在项目中将间接依赖排除在外,但两者实现机制却完全不一样。
- 排除依赖是控制当前项目是否使用其直接依赖传递下来的接间依赖;
- 可选依赖是控制当前项目的依赖是否向下传递;
- 可选依赖的优先级高于排除依赖;
- 若对于同一个间接依赖同时使用排除依赖和可选依赖进行设置,那么可选依赖的取值必须为 false,否则排除依赖无法生效。
仓库
任何一个依赖、插件或者项目构建的输出,都可以称为构建。坐标和依赖时任何一个构件在Maven世界中的逻辑表示方式,而构件的物理表示方式是文件。
Maven仓库是统一存储所有Maven项目共享的构件的位置。实际的Maven项目将不再各自存储其依赖文件,只需要声明这些依赖的坐标,在需要的时候,Maven会自动根据坐标找到仓库中的构件并使用
布局
仓库路径与坐标的大致对应关系为:groupId/artifactId/version/artifactId-version.packaging
分类
仓库只有两类:本地仓库和远程仓库。
Maven寻找构件过程:
- 查看本地仓库,若存在,直接使用
- 本地仓库不存在或需要查看是否有更新,Maven就需要去远程仓库查找,找到需要的构件后下载到本地再使用
- 若本地和远程仓库都找不到,则会报错
特殊的远程仓库:
- 中央仓库:Maven核心自带的远程仓库,包含了绝大部分开源的构件,在默认的配置下,当本地仓库没有需要的构件时会尝试从中央仓库下载
- 私服:为了节省宽带和时间,在局域网内假设的一个私有的仓库服务器,用其代理所有外部的远程仓库
- 其他公开的远程仓库
本地仓库
目录地址:settings.xml中标签设置,默认为~/.m2/repository/
构件下载到本地仓库的方式:①从Maven远程仓库下载,②mvn install将本地项目安装到仓库中
安装Maven后,如果不执行任何Maven命令ÿ