maven系列
阅读本文大约需要10分钟
Maven中的pom文件
Maven项目的核心是pom(project object model)文件
Maven项目结构
- src/main
- java 主代码目录
- resouces 资源文件目录
- src/test
- java 测试代码目录
- resouces 测试资源文件目录
maven的项目结构是是约定好的, 我们不是必须每次按照maven的约定的结构去新建项目,也可以通过maven提供的骨架生成我们需要的项目
pom文件
mavenpom文件的整体结构
<?xml version ="1.0" encoding ="utf-8" ?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.bread</groupId>
<artifactId>mtest</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>mtest</name>
</project>
Maven的坐标信息
- modelVersion
定义当前项目的遵循的模型版本 - groupid
当前项目的实际项目信息,不应该对应到公司或者组织,应该对应到公司或者组织下边某一实际项目 - artifactId
当前项目的模块信息 - version
当前模块的版本信息 - packaging
模块的打包类型,不定义packageing时,默认为jar - classifier
用来定义输出一些附属构件的,也可以理解为一套源码,输出成两套构件 - name
当前项目的一些描述信息
modelVersion | groupid | artifactId | version | packaging | classifier | name |
---|---|---|---|---|---|---|
3.0之后必须定义 | 必须定义 | 必须定义 | 必须定义 | 不定义默认jar | 不能直接定义 | 非必须定义 |
小结: 在maven项目中,项目结构是固定的,pom文件是核心配置文件,在pom文件中配置当前项目的坐标信息,通过坐标信息就可以定位到这个项目的位置,并且了解到一个项目坐标的定义必须有三个要素,
Maven 依赖详解
日常项目开发中,我们需要引入第三方的依赖,在传统的项目中,我们只能挨个网站去找,在maven提供了引入依赖的方法
在dependencies元素中,使用 dependency 元素引入依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
</dependency>
<dependencies>
- groupid artifactId version
maven的坐标信息和版本信息,组合定义唯一的仓库的依赖坐标信息 - type
type是指依赖的类型,对应坐标的 packageing 默认为jar - scope
scope是指依赖范围,指当前依赖的作用域,默认为compiler - optional
标记依赖是否可选,默认为false, - exclusions
排除依赖
依赖范围(scope)
maven项目目录分为主代码目录和测试代码目录
maven项目编译时分为三种classpath
- 编译classpath
主代码编译,也可以认为是 src/java 目录下代码编译范围 - 测试classpath
测试代码编译 src/test 目录下代码编译范围 - 运行classpath
主代码运行,可以理解为 打完包的class文件和lib
依赖范围是用来控制依赖于三种classpath的关系。
依赖范围
- complie
编译依赖范围,在三种依赖范围都有效 - test
测试依赖范围,在测试依赖范围和运行依赖有效 - provided
已提供依赖范围,项目在编译和测试时有用,但是在运行时是不必要的, 因为容器或者环境已经提供了该依赖,最常见的就是tomcat容器 - runtime
运行时依赖,该依赖范围对运行和测试时有用,对编译时没用,比如mysql的驱动,在编译时,并没有链接数据库,在实际运行或者测试用例的过程中才会链接数据库,使用驱动包 - system
系统级别依赖,使用依赖,必须使用systempath显示声明依赖位置,一般是用于和操作系统绑定 - import
导入依赖,在存在继承关系的pom中,子pom引入父级pom时使用
依赖范围表说明
编译 classpath | 测试classpath | 运行classpath | 例如 | |
---|---|---|---|---|
complie | Y | Y | Y | spring-core |
test | N | Y | N | junit |
provided | Y | Y | N | tomcat等web容器的 servlet-api |
runtime | N | Y | Y | JDBC驱动 |
system | Y | Y | N | 一般是本地有不用导入仓库的 |
以下分为别5种依赖范围的运行情况,我建议使用web项目打包观察
传递性依赖
在实际项目开发中,使用某一个依赖时,该依赖有可能又依赖于别人。
例如:项目A依赖 spring-core,;spring-core又依赖于spring-jcl,那么spring-jcl就是项目A的传递性依赖
maven引入传递性依赖机制,使得我们在项目中,不需要关心第三方类库的的依赖,也不必担心引入多余的依赖。maven会自动帮我们解析pom,将间接性依赖引入进来
传递性依赖依赖范围
假设A依赖于B,B又依赖于C ,那么A对于B来说就是第一依赖,C对于B来说就是第二依赖,A对于C来说就是传递性依赖
传递性依赖范围表
第二依赖范围 | |||||
---|---|---|---|---|---|
compiler | test | provided | runtime | ||
第一依赖范围 | compiler | compiler | 不传递 | 不传递 | runtime |
test | test | 不传递 | 不传递 | test | |
provided | provided | 不传递 | provided | provided | |
runtime | runtime | 不传递 | 不传递 | rumtime |
- 第二依赖范围是 complie ,那么传递性依赖范围就是和第一依赖范围保持一致;例:第二范围是 complie ,第一依赖是test, 那么传递性依赖就是test, 第一依赖是complile ,那么传递性依赖就是complile
- 第二依赖范围是 test时,依赖不进行传递
- 第二依赖范围是provided 时,只传递 第一依赖范围为 provided 的依赖,并且 依赖范围为 provided
- 第二依赖范围是 runtime 时, 传递性依赖范围与 第一依赖范围保持一致 ;第一依赖范围为complie除外,compile为runtime
了解依赖的依赖范围,和传递性依赖范围,可以很好解决我们项目在实际使用依赖臃肿的问题, 不是所有依赖必须配置为编译时依赖
依赖调节
假如
项目 A
引入了 A - > B ->C - X (1.0)
引入了 A - > D - X (2.0)
实际项目中用到的依赖X 用的是哪个版本呢?
- 依赖调解的第一原则,最短路径原则
因为 A - > D -> X 路径小于 A -> B -> C -> X ,因此 X (2.0)会被解析 - 依赖调解的第二原则,第一声明优先
假如 A- > D -> Y (1.0) 和 A -> C -> Y (2.0) 路径相同的情况下,谁先申明谁被解析,因此,Y (1.0)会被解析
在引入第一依赖中,版本号高的会被解析,但是不建议声明两个版本不同的依赖,在存在传递性依赖时,按照调解第一原则和第二原则进行加载
可选依赖
通过 optional 来标记当前依赖是否为可选依赖
在实际项目中有场景, A 依赖于B B依赖于 X 和 Y ;如果 X 和 Y 的依赖范围为 complier,那A的对于X和Y 的依赖范围也是 compiler,但是实际A项目中使用不到 X和Y ,就把X和Y 标记为 可选依赖,可选依赖不会进行传递
mysql-connector-java 没有被传递
排除依赖&归类依赖
- 排除依赖
排除依赖通过 exclusions 标签来排除依赖
在项目中,可能需要排除第三方依赖的传递性依赖,根据项目情况手动引入或者不引入,如果存在多级引入时,那么当前排除的依赖的引入的所有依赖,
fastjson 和 zookeeper被排除掉
- 归类依赖
归类依赖,就是把相同组织下同一项目的不同模块,按照同一版本号一起引入依赖
在项目使用过程中,用到spring 或者 netty 的框架时,往往需要依赖的模块比较多,如果每个模块按照不同的版本,引入到项目中,有可能造成框架不可用,或者版本不同的引起的BUG,大的开源框架迭代基本上所有模板一起迭代的,为了保障项目的依赖统一。通过全局属性,设定依赖的版本号
优化依赖
实际项目使用中,我们优化依赖时需要明白项目中到底引入哪些依赖,通过以下命令便可以分析;
通过以下命令来查看
-
mvn dependency:list
查看当前项目的依赖列表
-
mvn dependency:tree
查看当前项目的依赖树;树形展示 -
mvn dependency:analyze
Used undeclared dependencies found
项目中使用的依赖但是没有显式声明
Unused declared dependencies found
项目中声明的依赖但是没有使用到
重点看提示信息, Used undeclared dependencies found & Unused declared dependencies found
坐标和依赖是maven比较核心的两个概念,弄懂依赖机制,就能解决我们项目中实际的遇到的引入问题