标签:
一:依赖范围
Maven在编译项目主代码的时候需要使用一套classpath。其次,在编译和执行测试的时候会使用另外一套classpath。最后,实际运行Maven项目的时候,又会使用一套classpath。
所谓的依赖范围就是用来控制依赖与这三种classpath(编译、测试、运行)的关系,Maven有以下几种依赖范围:
<dependency> <groupId>javax.sql</groupId> <artifactId>jdbc-stdext</artifactId> <version>2.5</version> <scope>system</scope> <systemPath>${spath}/lib/test.jar<systemPath> </dependency>
二:传递依赖和依赖范围
当我们依赖一个a.jar时,如果a.jar依赖b.jar,那么只需要早pom中声明对a.jar的依赖即可,b.jar会被Maven自动加载进来。
例如:有一个org.springframework:spring-core:2.5.6的依赖,而实际上spring-core也有它自己的依赖,它依赖commons-logging。有了传递依赖机制,在使用spring-core时不需要考虑它依赖了什么。Maven会自动解析。
依赖范围在传递依赖时会略有变化
当第二直接依赖的范围是compile的时候,传递性依赖的范围与第一直接依赖的范围一致;
当第二直接依赖的范围是test的时候,依赖不会得以传递;
当第二直接依赖的范围是provided的时候,只传递第一直接依赖范围也为provi的依赖,且范围为provided;
当第二直接依赖的范围是runtime的时候,传递性的依赖范围与第一直接依赖的范围一致,但compile例外,此时传递依赖范围为runtime;
三:依赖调解
除以上两种原则外,还可以手动排除,例如:A ->B ->X(1.0)同时A ->X(2.0)。如果项目A希望加载X(2.0)可做如下声明,通过<exclusion>元素来显式排除。
<dependency> <groupId>com.xxx.xx</groupId> <artifactId>xx-B</artifactId> <version>2.5</version> <exclusions> <exclusion> <groupId>com.xx</groupId> <artifactId>project-X</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.xxx.xx</groupId> <artifactId>project-x</artifactId> <version>2.0</version> </dependency>
四:可选依赖
例如:b.jar是一个持久层工具包,它同时支持Mysql和PostgreSql,A项目依赖b.jar,那么在构建A时需要这两种数据库的驱动程序,但在使用的时候知会依赖一种数据库。A项目的依赖声明如下:
<dependency>
<groupId>com.xxx.xx</groupId>
<artifactId>xx.db</artifactId>
<version>2.5</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.10</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.4-701.jdbc3</version>
<optional>true</optional>
</dependency>
</dependencies>
</dependency>
使用<optional>元素表示这两个为可选依赖,这是依赖不会传递到A项目,当A项目需要使用基于MySQL数据库时,需要显式声明对mysql的依赖。
另外:在理想的情况下是不会出现这种情况的,因为在面向对象设计中,有一个单一职责原则,即一个jar的职责应该只有一个。所以对于b.jar,最好是创建2个Maven项目,分别实现mysql和postgresql。
五:依赖优化
代码需要不断重构才能达到最优,依赖管理也是一样,需要不断的进行去除多余依赖,以及显式的声明某些必要的依赖。
Maven会自动解析所有项目的直接依赖和传递依赖,并根据规则判断每个依赖的范围,对于一些依赖冲突也能进行调节,这些工作之后得到这个项目的完整的已解析依赖。
可通过运行以下命令查看当前项目的已解析依赖:
mvn dependency:list
上图展示了当前项目中所有已解析的依赖,同时每个依赖的范围也得以明确标示。
如果将直接在pom中声明的依赖定义为第一层依赖,这些顶层依赖的依赖定义为第二层依赖,则以此类推可以形成一个完整的依赖树。
可运行以下明细查看当前项目的依赖树
mvn dependency:tree
从上图中可以清晰看出,虽然没有声明slf4j-api,但它通过传递依赖被加载进来,其范围为compile。
可运行以下命令对当前项目依赖进行简单分析
上图中Used undeclared dependencies,表示项目中使用到的,但是没有显式声明的依赖。可以看到第一个依赖是SNAPSHOT版本,它是通过传递依赖被加载进来的,这种依赖就是项目中的隐藏的、潜在的炸弹,因为引用的是SNAPSHOT非稳定版本,且不在pom中显式声明,很容易被忽略。该炸弹一旦爆炸,往往需要耗费大量时间来查明。
还有一个Unused declared dependencies,表示项目中未使用的,但是显式声明的依赖。如果真的不需要,建议去除声明。但需要注意的是,dependency:analyze知会分析编译和测试时需要用到的依赖,一些运行时依赖就无法被发现。所以在优化依赖时一定要小心测试。
标签:
原文地址:http://www.cnblogs.com/qt2136/p/4507725.html