您的位置:首页 > 其它

一起学Maven(Maven的依赖管理特性)<三>

2016-07-29 00:00 351 查看

前情回顾

在上一节中介绍了通过工具eclipse构建了maven项目,并且仅仅做了简单的运行演示,本节将通过eclipse构建出一个项目中的几个模块,并且通过这几个模块的联系讲解maven中依赖的特性。

项目构建

本章通过一个典型的项目构建过程来学习Maven的依赖传递性。

项目获取地址http://download.csdn.net/detail/songdeitao/6927445

总共分为三个模块的项目编写user-core,user-log,user-service,在user-core中主要实现基本的实体类,初始文件,dao的编写,在user-log中简单模拟日志文件的记录,在user-service模块中主要引入前两个模块,从而进行编写service模块的功能,在这里模块的编写不是重点,这些都会给出代码,然而进行Maven依赖与传递的讲解才是重点,所以很多时候代码都是为了演示出效果,和实际开发还是有些差别,但所指代的思想是项目中所存在的。

普通依赖
Maven的依赖是使用Maven坐标来定位的,而Maven坐标主要由GAV(groupId, artifactId, version)构成,因此,使用任何一个依赖之间,你都需要知道它的Maven坐标,在之前的第二章节中,从引入了Maven的中央工厂的网页,在此引入一个常用的Maven搜索jar包的资源库网页http://www.mvnrepository.com/,在此可以查找所需要的jar文件的GAV,比如在本文的第一章节的如下配置:

<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency>


可以通过如下列图所示的步骤进行查找到,而且以后的jar包查找过程都是按照此步骤进行获取,然后复制到pom.xml<dependencies>元素下,Maven就能在本地或者远程仓库中找到对应的jar包(不一定可以找到所有的jar文件)



图1



图2



图3

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

一:

首先紧跟第二章节的新建项目构建出如下图所示的结构图,



图4

通过此模块的构建,主要说明Maven的一下几个问题

1、目录结构的默认构建,比如资源文件的src/main/resources目录的构建

2、pom.xml文件的使用到的jar包的引入,比如在user-core中的文件内容如下所示:

<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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>

<groupId>com.steven.user</groupId>
<artifactId>user-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>user-core</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.1.1.Final</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.8</version>
</dependency>

</dependencies>
</project>

通过资源库中查找到相应的jar包,放到pom.xml中之后,Eclipse就会自动会和本地资源库或者
远程仓库中进行匹配,如果本地中没有,就会通过网络下载从远程仓库中下载到本地仓库中。

3、进行Maven项目模块的打包和加入到本地资源库的命令,如图所示



图5

这样就可以执行打包或者将打包后的jar添加到本地仓库中。

二:

接着引入user-log,user-service





图6 图7

其中user-log的pom.xml如下所示

<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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>

<groupId>com.steven.user</groupId>
<artifactId>user-log</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>user-log</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.4</version>
</dependency>
</dependencies>
</project>

其中user-service的pom.xml如下所示

<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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>

<groupId>com.steven.user</groupId>
<artifactId>user-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>user-service</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>user-log</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>user-core</artifactId>
<version>${project.version}</version>
</dependency>

</dependencies>
</project>


此时细心的读者会发现在user-service的pom文件中出现${project.groupId}和${project.version}的写法,这是Maven的内置隐式变量,常用的如下介绍:

${basedir} 项目根目录
${project.build.directory} 构建目录,缺省为target
${project.build.outputDirectory} 构建过程输出目录,缺省为target/classes
${project.build.finalName} 产出物名称,缺省为${project.artifactId}-${project.version}
${project.packaging} 打包类型,缺省为jar
${project.xxx} 当前pom文件的任意节点的内容(这里所使用到的)

注意:

在完成user-service对user-log和user-service模块的jar包引入的时候,一定要将这两个模块进行install处理,这样在user-service中才可以访问到前两个模块的jar包。

传递依赖
此时打开user-service的pom的dependency hierarchy图,如图所示:



图8

会发现在user-log中使用log4j-1.2.4.jar而user-core中使用log4j-1.2.14.jar,但user-service包含user-log和user-core后,所使用的是log4j-1.2.4,为什么不使用新的版本呢?

这是因为我在user-service中将user-log写在了user-core前面。但难道谁写在前面就在前面了吗?

那我就将这两个配置调换一下,得到的图如图9所示



图9

再看log4j变成了log4j-1.2.14.jar(图中没有标出,但不难看出),那确实是这样吗?然后看图8中dom4j是1.5版本,在图9中调换过位置后还是1.5版本,怎么回事?细心的读者会发现log4j是出于user-core和user-log的同一级别,而dom4j在user-core和user-log却不是在同一级别。

奥,我明白了,原来是这么一回事:

结论:

1、当依赖的级别相同时,引入最先导入的jar包

2、当依赖级别不同时候,引入级别最近的jar包

那我偏要使用dom4j1.6.1的版本,那怎么办呢?

排除依赖
Maven很智能,在此提供一个元素,exclusion,只要在不想要的模块中添加此元素,比如不想要user-log的dom4j1.5版本,则只要在user-service中这样编写即可:

<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>user-log</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
</exclusion>
</exclusions>
</dependency>

此时在查看
user-service的pom的dependency hierarchy图,发现已经成功使用dom4j1.6.1版本了,如图所示



图10

依赖范围(scope)
读者还会发现,在图8,9,10中,每个jar后都有类似[compile]的标识,这是什么意思呢?这里将引入Maven的依赖范围概念。

什么是依赖范围呢?

引入:

Maven在编译主代码的时候需要使用一套classpath,在编译和执行测试的时候会使用另一套classpath,实际运行项目的时候,又会使用一套classpath。
依赖范围就是用来控制依赖与这三种classpath(编译classpath、测试classpath、运行classpath)的关系,

Maven有以下几种依赖范围:
compile: 编译依赖范围。

如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效。

test: 测试依赖范围。

使用此依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目的使用时将无法使用此类依赖。典型的例子就是JUnit,它只有在编译测试代码及运行测试的时候才需要。这也是本文的pom文件中为何junit的scope是使用test范围的原因。

provided: 已提供依赖范围。

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

runtime: 运行时依赖范围。

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

注意:以上四种范围是开发中常用的配置,而以下两种都是不要求的,使用的很少,了解即可

system: 系统依赖范围。

该依赖与三种classpath的关系,和provided依赖范围完全一致。但是,使用system范围依赖时必须通过systemPath元素显式地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。

import(Maven 2.0.9及以上): 导入依赖范围。

总结

至此,对于Maven的依赖性已经讲解差不多了,余下的在开发中很少使用到,所以掌握以上内容已经足够使用了,而且Maven的依赖算是Maven的学习中的一个难点,因此需要自己手动创建项目进行测试验证。

在此,一样恭祝大家学习愉快,新年快乐!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: