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

前情回顾

    在上一节中介绍了通过工具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,比如在本文的第一章节的如下配置:


	junit
	junit
	4.10

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

一起学Maven(Maven的依赖管理特性)_第1张图片

                        图1

一起学Maven(Maven的依赖管理特性)_第2张图片

                        图2

一起学Maven(Maven的依赖管理特性)_第3张图片

                         图3

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

传递依赖

一:

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

一起学Maven(Maven的依赖管理特性)_第4张图片

          图4

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

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

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


	4.0.0

	com.steven.user
	user-core
	0.0.1-SNAPSHOT
	jar

	user-core
	http://maven.apache.org

	
		UTF-8
	

	
		
			junit
			junit
			4.10
			test
		

		
			log4j
			log4j
			1.2.14
		

		
			org.hibernate
			hibernate-core
			4.1.1.Final
		

		
			mysql
			mysql-connector-java
			5.1.8
		


	

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

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

一起学Maven(Maven的依赖管理特性)_第5张图片

                    图5

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

二:

接着引入user-log,user-service

一起学Maven(Maven的依赖管理特性)_第6张图片一起学Maven(Maven的依赖管理特性)_第7张图片

           图6                            图7

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


	4.0.0

	com.steven.user
	user-log
	0.0.1-SNAPSHOT
	jar

	user-log
	http://maven.apache.org

	
		UTF-8
	

	
		
			junit
			junit
			4.10
			test
		

		
			dom4j
			dom4j
			1.5
		
		
			log4j
			log4j
			1.2.4
		
	

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


	4.0.0

	com.steven.user
	user-service
	0.0.1-SNAPSHOT
	jar

	user-service
	http://maven.apache.org

	
		UTF-8
	

	
		
			junit
			junit
			4.10
			test
		
		
			${project.groupId}
			user-log
			${project.version}
		
		
		
			${project.groupId}
			user-core
			${project.version}
		
		
	

    此时细心的读者会发现在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图,如图所示:

一起学Maven(Maven的依赖管理特性)_第8张图片

                      图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所示

一起学Maven(Maven的依赖管理特性)_第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中这样编写即可:


			${project.groupId}
			user-log
			${project.version}
			
				
					dom4j
					dom4j
				
			
		
             此时在查看 user-service的pom的dependency  hierarchy图,发现已经成功使用dom4j1.6.1版本了,如图所示

一起学Maven(Maven的依赖管理特性)_第10张图片

                     图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的学习中的一个难点,因此需要自己手动创建项目进行测试验证。

    在此,一样恭祝大家学习愉快,新年快乐!



你可能感兴趣的:(项目开发)