Maven依赖的配置

Maven的依赖配置有基本的groupId,artifactId和version等元素组成,其实一个依赖声明可以包含如下的
一些元素
    <project>
        ...
        <dependencies>
            <dependency>
                <groupId>...</groupId>
                <artifactId>...</artifactId>
                <version>...</version>
                <type>...</type>
                <scope>...</scope>
                <optional>...</optional>
                <exclusions>
                    <exclusion>
                    ...
                    </exclusion>
                <exclusions>
            </dependency>
            ...
        <dependencies>
    </projects>

依赖元素介绍
    根元素project下的dependencies可以包含一个或者多个dependency元素,以声明一个或多个
    项目依赖。每个依赖可以包含的元素有:
    groupId,artifactId和version:依赖的基本坐标,对于任何一个依赖来说,基本坐标是最重要
        的,Maven根据坐标才能找到需要的依赖。

    type:依赖的类型,对应于项目坐标定义的packaging.大部分情况下,该元素不必声明,其默认值
        为jar

    scope:依赖的范围,如test,compile,provided

    optional:标记依赖是否可选

    exclusions:用来排除传递性依赖

    大部分依赖声明只包含基本坐标,然而在一些特殊情况下,其他元素至关重要。

依赖范围
    Maven在编译项目主代码的时候需要使用一套classpath.

    Maven在编译和执行测试的时候会使用另外一套classpath。

    Maven实际运行项目的时候,又会使用一套classpath。

    依赖范围就是用来控制依赖与这三种classpath(编译classpath,测试classpath,运行classpath)的关系,
    Maven有以下几种依赖范围:
    compile:编译依赖范围,如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译,测试,运行三种
        classpath都有效。典型的例子是spring-core

    test:测试依赖范围。使用此依赖范围的Maven依赖,只对于测试classpath有效。典型的例子是JUnit

    provided:已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效
        典型的例子是:servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经提供,就不需要
        Maven重复地引入一遍。

    runtime:运行时依赖范围,使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。
        典型的例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现
        上述接口的具体JDBC驱动。

    systemm:系统依赖范围。该依赖范围与三种classpath的关系,和provided依赖范围完全一致。但是,使用system范围的依赖时必须通过
        systemPath元素显式的指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成
        构建的不可移植,因为应该谨慎使用。systemPath元素可以引用环境变量,如
        <dependency>
            <groupId>javax.sql</groupId>
            <artifactId>jdbc-stdext</artifactId>
            <version>2.0</version>
            <scope>system</scope>
            <systemPath>${java.home}/lib/rt.jar</systemPath>
        <dependency>

    import:(Maven2.0.9及以上):导入依赖范围,该依赖范围不会对三种classpath产生实际的影响,此依赖范围只在dependencyManagement
        元素下才有效,使用该范围的依赖通常指向一个pom,作用是将目标POM中的dependencyManagement配置导入并合并到当前POM的
        dependencyManagement元素中。

        import范围依赖由于其特殊性,一般都是指向打包类型的pom的模块,如果有多个项目,它们使用
        的依赖版本都是一致的,则就可以定义一个使用dependencyManagement专门管理依赖的POM,然后
        在各个项目中导入这些依赖管理配置

        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>com.catt.account</groupId>
                    <artifactId>account-parent</artifactId>
                    <version>1.0-SNAPSHOT</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>

传递性依赖和依赖范围
    依赖范围不仅可以控制依赖与三种classpath的关系,还对传递性依赖产生影响。
    如account-email对于spring-core的依赖范围是compile,spring-core对于commons-logging的依赖范围是compile,那么account-email对于commons-logging
    这一传递性依赖的范围也就是compile。
    假设A依赖于B,B依赖于C,则A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖。第一直接依赖的范围和第二直接依赖的范围决定了传递性
    依赖的范围

    Maven会解析各个直接依赖的POM,将那些必要的间接依赖以传递性依赖的形式引入到当前的项目中。

    规律如下:
    当第二直接依赖的范围是compile的时候,传递性依赖的范围与第一直接依赖的范围一致;
    当第二直接依赖的范围是test的时候,依赖不会得以传递;
    当第二直接依赖的范围是provided的时候,只传递第一直接依赖的范围也为provided的依赖,且传递性依赖的范围同样为provided;
    当第二直接依赖的范围是runtime的时候,传递性依赖的范围与第一直接依赖的范围的范围一致,但compile例外,此时传递性依赖的范围为runtime;

依赖调解
    Maven引入的传递性依赖机制,一方面大大简化和方便了依赖声明,另一方面,大部分情况下我们只需要关心项目的直接依赖是什么,而不用考虑这些直接依赖会引入
    什么传递性依赖。但有时候,当传递性依赖造成问题的时候,就需要清楚地知道该传递性依赖是从哪条依赖路径引入的

    依赖调解(Dependency Mediation)的原则有两个,如下:(为了避免针对同个构件的重复引入)
    第一原则:路径最近者优先
    第二原则:第一声明优先。 即在依赖路径长度相等的前提下,在POM中依赖声明的顺序决定了谁会被解析使用,顺序最靠前的那个依赖优先。

可选依赖
    假设有这样一个依赖关系,项目A依赖于项目B,项目B依赖于项目X和项目Y,B对于项目X和Y的依赖都是可选依赖。根据传递性依赖的定义,如果所有这三个依赖的范围都是
    compile,那么X\Y就是A的compile范围传递性依赖,然而,由于这里X\Y是可选依赖,依赖将不会得以传递,换句话说,X\Y将不会对A有任何影响。

    在理想的情况下,是不应该使用可选依赖的。
    使用可选依赖的原因是某一个项目实现了多个特性,如项目是一个持久层隔离工具包,支持多种数据如MYSQL,SYBASE,在构建这个工具包的时候,需要这两种数据库的驱动
    程序,但在使用这个工具包的时候,只会依赖一种数据库。

排除依赖
    传递性依赖会给项目隐式地引入很多依赖,这极大的简化了项目依赖的管理,但有时这种特性也会带来问题。

    声明exclusion的时候只需要groupId和artifactId,而不需要version元素,这是因为只需要groupId和artifactId就能唯一确定依赖图中的某个依赖。

    排除依赖:
    排除不稳定的传递性依赖构件,另外再显式在当前项目中声明该类库的某个正式发布的版本。
    想替换某个传递性依赖,比如Sun JTP API,Hibernate依赖于这个JAR,但是由于版本的因素,该类库不在中央仓库中,而Apache Geronimo项目有一个对应的实现
        这时就可以排除Sun JAT API,再声明Geronimo的JTA API的实现

归类依赖
    如果一个项目依赖同一项目的多个不同模块,如一个项目依赖springframework的多个模块,因为这些依赖的版本都是相同的,且可以预见,如果将来需要升级,则这些
    依赖的版本会一直升级。

    这样可以定义maven的属性,然后通过${}的方式引用

优化依赖
    Maven会自动解析所有项目的直接依赖和传递性依赖,并且根据规则正确判断每个依赖的范围,对于一些依赖,
    也能进行调节,以确保任何一个依赖只有唯一的版本在依赖中存在,在这些工作之后,最后得到的那些依赖被称为
    已解析依赖(Resolved Dependency). 可以运行如下命令查看当前项目的已解析依赖
    mvn dependency:list
    mvn dependency:tree
    mvn dependency:analyze

坐标和依赖是任何一个构件在Maven世界中的逻辑表达方式;而构件的物理表示方式是文件,Maven通过仓库来统一管理这些文件

你可能感兴趣的:(maven,配置,依赖)