Maven依赖分析

来源:互联网 发布:电子竞技数据分析 编辑:程序博客网 时间:2024/06/10 14:58

依赖结构

之前提到可以用maven 命令查看项目的依赖结构,比如输入一下命令

mvn dependency:tree
maven 就把我们项目依赖结果输出成树的结构。

[INFO] +- thirdparty_tools:Spring:pom:3.0.5_full:compile[INFO] |  +- thirdparty_lib:org.springframework.aop:jar:3.0.5_full:compile[INFO] |  +- thirdparty_lib:org.springframework.asm:jar:3.0.5_full:compile[INFO] |  +- thirdparty_lib:org.springframework.aspects:jar:3.0.5_full:compile


声明

上面的输出涉及到几个概念。下面简单说下。
一般情况下我们会在 pom.xml 中设置下面类似的依赖。
<dependency><groupId>thirdparty_lib</groupId><artifactId>commons-jexl</artifactId><version>2.1.1</version><type>jar</type><scope>compile</scope><exclusions><exclusion><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId></exclusion></exclusions></dependency>
groupId、artifactId 和 version 很简单啦,就是一个jar包的坐标,maven就是根据这个信息在本地仓库或远程仓库中找到指定的jar包的。
type : 依赖类型。大部分情况下不需要这个声明,默认jar。
scope : 依赖范围。
exclusions : 用来排除传递依赖。
其实,大部分依赖我们只需要声明坐标即可。


下面说下几个概念。

classpath

相信很多人对这个不默认吧。用于告诉Java执行环境,在哪些目录下可以找到您所要执行的Java程序所需要的类或者包。简单的来说就是一些包和类的集合。
其实maven在帮我们完成工作时,不同时期的classpath有所不同。

1. Maven在编译项目主代码的时候需要使用一套 classpath。 
2. 之后 Maven在编译和执行测试的时候会使用另外一套 classpath。
3. 最后实际运行 Maven项目的时候,又会使用一套 classpath.
也就是说我们在使用Maven时,一共会涉及三套 classpath。


依赖范围

上面 dependency 里面 scope 的声明就是指名 依赖范围。
而依赖范围就是用来控制依赖的当前jar包与这三种 classpath (编译classpath,测试 classpath,运行classpath) 的关系。


依赖范围有如下几种
compile:编译依赖范围。默认使用。对于三种classpath都有效。spring-core
test:测试依赖范围。只对 测试classpath有效。编译代码或运行时无法使用此类依赖。JUnit。编译测试代码和运行测试的时候需要。
provided:已提供依赖范围。即运行环境所在容器已经提供。可知 对于 编译和测试classpath有效。运行时无效。 servlet-api.
runtime:运行时依赖。该范围的依赖对于测试运行classpath有效,对于编译主代码无效。 JDBC驱动。我们知道编译代码只需要JDK的JDBC接口即可。而JDBC驱动是上述接口的实现。所以执行测试或运行项目时才会需要。
system:系统依赖范围。其支持的classpath与provided依赖范围一致。只是不通过maven仓库解析。而是通过systemPath 元素显示指定依赖文件的路径。因此为了系统构建可以多处运行,不建议使用此依赖范围。

<dependency><groupId>javax.sql</groupId><artifactId>jdbc-stdext</artifactId><version>2.0</version><scope>system</scope><optional></optional><systemPath>${java.home}/lib/rt.jar</systemPath></dependency>
综合上述,依赖范围与 classpath 的关系如下:

依赖范围对编译classpath有效对测试classpath有效对运行时classpath有效举例compileYYYspring-coretest Y JUnitprovidedYY servlet-apiruntime YYJDBC驱动的实现,如oracle_jdbc.jarsystemYY 本地环境变量中的jar

传递性依赖

我们知道,很多jar包都是有依赖的,比如 A 依赖 B,而B依赖 C,也就是我们所说的A 间接依赖 C。即 A => B => C。此时 C就是 A的一个传递性依赖。在项目中,我们不需要考虑传递性依赖,maven的传递性依赖会解析我们的间接依赖,并将它们引入我们的项目。


这里说下,依赖范围对传递性依赖是有影响的。当依赖关系是 A => B => C 时,我们假定 A => B 为第一依赖,B => C为第二依赖。这里将它们列成表格,第一列是第一依赖,第一行是第二依赖。因此就会组合成如下传递性依赖范围的范围。


 compiletestprovidedruntimecompilecompile  runtimetesttest  testprovidedprovided providedprovidedruntimeruntime  runtime空白意味不依赖

下面举个例子,下面是两个Project,mavenprjA 和 mavenprjB。各自 pom.xml如下

mavenprjA 

<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/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com</groupId><artifactId>mavenprjA</artifactId><packaging>jar</packaging><version>0.0.1-SNAPSHOT</version><name>my Maven Webapp</name><url>http://maven.apache.org</url><dependencies><dependency><groupId>com</groupId><artifactId>mavenprjB</artifactId><version>0.0.1-SNAPSHOT</version><scope>test</scope><!------------------A ----------------></dependency><!-- Test start --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- Test end --></dependencies></project>


mavenprjB

<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/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com</groupId><artifactId>mavenprjB</artifactId><packaging>jar</packaging><version>0.0.1-SNAPSHOT</version><name>my Maven Webapp</name><url>http://maven.apache.org</url><dependencies><!-- Util --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.4</version><scope>test</scope><!------------------B ----------------></dependency></dependencies></project>

从上面可以发现,mavenprjA => mavenprjB, 而 mavenprjB => org.apache.commons.commons-lang3,依赖范围都是 test。 查看 mavenprjA 的依赖树。

从下面输出看,当我们设置第一依赖scope 为test 时,mavenprjA的依赖树中,mavenprjB下是没有commons-langs 的即是不传递的。

[INFO] ------------------------------------------------------------------------[INFO] Building my Maven Webapp 0.0.1-SNAPSHOT[INFO] ------------------------------------------------------------------------[INFO][INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ mavenprjA ---[INFO] com:mavenprjA:jar:0.0.1-SNAPSHOT[INFO] +- com:mavenprjB:jar:0.0.1-SNAPSHOT:test[INFO] \- junit:junit:jar:4.12:test[INFO]    \- org.hamcrest:hamcrest-core:jar:1.3:test[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------

然后我们不停地改变A、B 两处依赖的 scope,然后查看依赖树。就可以验证了。

原创粉丝点击