有人认为Maven是一个依赖管理工具,当然这种想法是错误的(确切的说Maven是一个项目管理工具,贯穿了整个项目生命周期,编译,测试,打 包,发布...),但Maven给人造成这种错误的印象也是有原因的,因为Maven的依赖管理十分强大,用好了Maven,你不再需要面对一大堆jar 感到头大,依赖冲突,无用依赖等问题也能够得到有效的防止和解决。

最简单的依赖

    依赖是使用Maven坐标来定位的,而Maven坐标主要由GAV(groupId, artifactId, version)构成。因此,使用任何一个依赖之间,你都需要知道它的Maven坐标。

最简单的依赖如:

Xml代码  Maven管理依赖_项目管理

<dependency>  

    <groupId>junit</groupId>  

    <artifactId>junit</artifactId>  

    <version>4.4</version>  

</dependency>  

    上例中我们声明了一个对junit的依赖,它的groupId是junit, artifactId是junit, version是4.4。这一组GAV构成了一个Maven坐标,基于此,Maven就能在本地或者远程仓库中找到对应的junit-4.4.jar文件。

依赖归类

    随着项目的增大,你的依赖越来越多,比如说你依赖了一堆spring的jar,有org.spring.framework:spring- core, org.spring.framework:beans, org.spring.framework:spring-web, org.spring.framework:spring-mock。它们的groupId是相同的,artifactId不同。为了管理其版本,你对它 们进行过统一的升级,逐个的将version改成了最新版。但是,显然,当POM很大的时候你说不定会犯错误,而当版本不一致的时候,一些诡异的兼容性问 题就可能出现。

对此,Maven有它的解决方案:

Xml代码  Maven管理依赖_项目管理

<dependencies>  

    <dependency>  

        <groupId>org.spring.framework</groupId>  

        <artifactId>spring-core</artifactId>  

        <version>${spring.version}</version>  

    </dependency>  

    <dependency>  

        <groupId>org.spring.framework</groupId>  

        <artifactId>spring-beans</artifactId>  

        <version>${spring.version}</version>  

    </dependency>  

    <dependency>  

        <groupId>org.spring.framework</groupId>  

        <artifactId>spring-web</artifactId>  

        <version>${spring.version}</version>  

    </dependency>  

    <dependency>  

        <groupId>org.spring.framework</groupId>  

        <artifactId>spring-mock</artifactId>  

        <version>${spring.version}</version>  

    </dependency>  

</dependencies>  

  

<properties>  

    <spring.version>2.5</spring.version> 

</properties>  

    这里我们定义了一个Maven属性,其名称为spring.version,值是2.5。在这个POM中,我们就能 用${spring.version}的方式来引用该属性。我们看到,所有spring相关的依赖的version元素现在都成 了${spring.version},当Maven运行的时候,它会自动用值2.5来替换这个引用。当我们需要升级spring的时候,只要更改一个地方便可,而且,你现在能很高的保证所有的spring依赖包都是同一个版本。

依赖范围(scope)

    本文的第一个例子其实是有漏洞的,对于Junit,一般来说你只有在运行测试的时候需要它,也就是说,它对于src/main/java的classpath没什么意义,并且,将Junit的jar文件打入最终的发布包也不是好事,这无谓的增加了发布包的大小。

其实我们应该这样做:

Xml代码  Maven管理依赖_项目管理

<dependency>  

    <groupId>junit</groupId>  

    <artifactId>junit</artifactId>  

    <version>4.4</version>  

    <scope>test</test>  

</dependency>  

    于是,junit对于主源码classpath不可用,对于测试源码classpath可用,不会被打包。

    再举个例子,在开发javaee应用的时候我们一定会用到servlet-api,它对于主源码和测试源码都是必要的,因为我们的代码中会引入 servlet-api的包。但是,在打包的时候,将其放入WAR包就会有问题,因为web容器会提供servlet-api,如果我们再将其打包就会造 成依赖冲突,解决方案如下:

Xml代码  Maven管理依赖_项目管理

<dependency>  

    <groupId>javax.servlet</groupId>  

    <artifactId>servlet-api</artifactId>  

    <version>2.4</version>  

    <scope>provided</scope>  

</dependency>  

    将依赖范围设置成provided,就意味着该依赖对于主源码classpath,以及测试classpath可用,但不会被打包。这正是servlet-api所需要的。

这里归纳一下主要的依赖范围以及作用:

 

依赖范围(scope)主源码classpath可用测试源码classpath可用会被打包
compile 缺省值TRUETRUETRUE
testFALSETRUEFALSE
runtimeFALSETRUETRUE
providedTRUETRUEFALSE


需要注意的是,当我们没有声明依赖范围的时候,其默认的依赖范围是compile。