4,maven坐标和依赖

一. 何为maven坐标

      Maven 定义了这样一组规则:世界上任何一个构件都可以使用 Maven 坐标唯一标识, Maven 坐标的元素包括 groupId artifactId  version  packaging  classifier 

    Maven 内置了一个中央仓库的地址( http://repo1.maven.org/maven2 ),该中央仓库包含了世界上大部分流行的开源项目构件, Maven 会在需要的时候去那里下载。

二. 坐标详解

      groupId 定义了当前 Maven 项目隶属的实际项目。一个实际项目往往会被划分成很多模块,一个模块可能就是一个Maven 项目。 goupId 不应该对应项目隶属的组织或公司,因为一个组织或公司可能会有多个实际项目。 groupId 的表示方式与 Java 包名类似。

      artifactId 定义实际项目中的一个 Maven 项目(模块)。推荐使用实际项目名作为 artifactId 的前缀,如: nexus-indexer 。因为默认情况下 Maven 生成的构件会以 artifactId 开头,用实际项目名作为前缀就能方便从一个 lib 文件夹中找到某个实际项目的一组构件。

      version 定义了当时 Maven 项目所处的版本。

      packaging 定义了 Maven 项目的打包方式,通常与所生成构件的文件扩展名对应。不同的打包方式会影响构建的生命周期。比如 jar 打包与 war 打包会使用不同的命令。不定义 packaging 的时候,默认为 jar 。( package  "maven-plugin" 的构件扩展名是 jar 

      classifier 定义构建输出的一些附属构件。附属构件与主构件对应。如 Java 项目的 javadoc  sources  TestNG 项目默认是基于 Java 1.4 平台的,而它又提供了一个 jdk5 的附属构件。我们不能直接定义项目的 classifier ,因为附属构件不是项目直接默认生成的,而是由附加的插件帮助生成的。

      groupId  artifactId  version 是必须定义的, packaging 是可选的, classifier 是不能直接定义的。

    项目构件的文件名与坐标相对应,一般为: artifactId-version[-classifier].packaging

三. 依赖的配置

    根元素 project 下的 dependencies 可以包含一个或者多个项目依赖。一个依赖声明可以包含如下的一些元素:

<dependency>  
   <groupId>…</groupId>  
   <artifactId>…</artifactId>  
   <version>…</version>  
   <type>…</type>  
   <scope>…</scope>  
   <optional>…</optional>  
   <exclusions>  
     <exclusion>…</exclusion>  
     …  
   </exclusions>  
</dependency>

      groupId  artifactId  version 是依赖的基本坐标。

    type 为依赖的类型,对应于项目坐标定义的 packaging 

    scope是依赖的范围。 

      optional 标记依赖是否是可选的。 

      exclusions 用来排除传递性依赖。

四. 依赖范围

    依赖范围包含:

        compile :编译依赖范围。对于编译、测试、运行三种 classpath 都有效。是默认的依赖范围。

        test :测试依赖范围。只对测试 classpath 有效。如 Junit

        provided :已提供依赖范围。只对编译、测试 classpath 有效。如 servlet-api ,运行时容器已提供。

        runtime :运行依赖范围。只对测试和运行 classpath 有效。如 JDBC 驱动实现,编译主代码时只需要 JDK 提供的JDBC 接口。

        system :系统依赖范围。与 Provided 依赖范围一致。但依赖是通过 systemPath 元素显式指定文件的路径,与本机系统绑定,一般无法移植。

        import :导入依赖范围。不会对 3  classpath 产生实际影响。

五. 传递性依赖

      Maven 会解析各个直接依赖的 POM, 将那些必要的间接依赖,以传递性依赖的形式引入到当前的项目中。假设 A 依赖 B  B 依赖 C ,我们称 A  B 是第一直接依赖, B  C 是第二直接依赖, A  C 是传递依赖。

六. 依赖调解

    依赖调解第一原则:路径最近者优先

        如:依赖关系为:A->B->C->X(1.0) A->D->X(2.0)  

        结果是X(2.0)会被解析使用。

    依赖调解第二原则:最先声明者优先。

        如:A->B->X(1.0)A->D->X(2.0)  B  D 先声明

        结果是 X(1.0)会被解析使用。

七. 可选依赖

    如果项目 B 实现了两个特性,特性一依赖于项目 X ,特性二依赖于项目 Y ,而 X  Y 是互斥的。(比如 B 是一个持久层隔离包,支持多种数据库, X  MySQL 驱动, Y  PostgreSQL 驱动。)那么 X  Y  B 的可选依赖。如果 A依赖 B ,则 A 不再传递依赖 X  Y 而需要显式地声明 X  Y 为其直接依赖。

    在理想情况下,是不应该使用可选依赖的。因为在面向对象设计中,有个单一职责性原则,意指一个类应该只有一项职责,而不是糅合太多的功能。这个原则在规划maven项目的使用同样适用。在上段文字的说明中,更好的做法是为MysqlPostgreSQL 分别创建一个maven项目

八. 最佳实践

1. 排除依赖

    有时候希望排除某些传递依赖(比如传递依赖因版权限制不可用或者传递依赖是个 SNAPSHOT 版本)而显示地声明他们的替代者。可以在 <exclusion> 中声明相排除的传递依赖,而多增加一个 <dependency> 声明它的替代者。<exclusion> 只用声明 groupId  artifactId 就行。

2. 归类依赖

    对于来自同一个实际项目的多个项目依赖,他们版本应该是一致的,这样,可以先用 <properties> 定义一个版本号变量。如:

        <properties><spring.version>2.5.6</spring.version></properties> 

    然后在版本信息的位置使用 ${spring.version} 来引用它。

3. 优化依赖

    可以执行 mvn dependency:list  mvn dependency:tree 查看已解析的依赖( resolved dependency )

    可以执行 mvn dependency:analyze 来分析项目中的直接用到但未显示声明的依赖( Used undeclared dependencies )和声明了但未用到的依赖( Unused declared dependencies )。 Used undeclared dependencies是项目直接用到了,但通过传递依赖引入的项目,这样当项目的直接依赖更新时,传递依赖也会随之更新,从而会导致项目代码与传递依赖不兼容。 Unused declared dependencies 并不是完全没用的依赖,只是在编译主代码和测试代码时没用,但可能会在执行测试和运行时用到。



你可能感兴趣的:(4,maven坐标和依赖)