maven-管理依赖-理论篇

     喜欢看英文文档的同志 看这里 (看我~

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

最简单的依赖

依赖是使用Maven坐标来定位的,而Maven坐标主要由GAV(groupId, artifactId, version)构成。因此,使用任何一个依赖之间,你都需要知道它的Maven坐标,关于如何寻找Maven坐标,《搜索Maven仓库》 一文可以帮助你。

最简单的依赖如:

Xml代码
  1. <dependency>  
  2.   <groupId>junit</groupId>  
  3.   <artifactId>junit</artifactId>  
  4.   <version>4.4</version>  
  5. </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代码
  1. <dependencies>  
  2.   <dependency>  
  3.     <groupId>org.spring.framework</groupId>  
  4.     <artifactId>spring-core</artifactId>  
  5.     <version>${spring.version}</version>  
  6.   </dependency>  
  7.   <dependency>  
  8.     <groupId>org.spring.framework</groupId>  
  9.     <artifactId>spring-beans</artifactId>  
  10.     <version>${spring.version}</version>  
  11.   </dependency>  
  12.   <dependency>  
  13.     <groupId>org.spring.framework</groupId>  
  14.     <artifactId>spring-web</artifactId>  
  15.     <version>${spring.version}</version>  
  16.   </dependency>  
  17.   <dependency>  
  18.     <groupId>org.spring.framework</groupId>  
  19.     <artifactId>spring-mock</artifactId>  
  20.     <version>${spring.version}</version>  
  21.   </dependency>  
  22. </dependencies>  
  23.   
  24. <properties>  
  25.   <spring.version>2.5</spring.version>  
  26. </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代码
  1. <dependency>  
  2.   <groupId>junit</groupId>  
  3.   <artifactId>junit</artifactId>  
  4.   <version>4.4</version>  
  5.   <scope>test</test>  
  6. </dependency>  

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

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

Xml代码
  1. <dependency>  
  2.   <groupId>javax.servlet</groupId>  
  3.   <artifactId>servlet-api</artifactId>  
  4.   <version>2.4</version>  
  5.   <scope>provided</scope>  
  6. </dependency>  

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

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

 

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

 

英文介绍:

Dependency Scope

Dependency scope is used to limit the transitivity of a dependency, and also to affect the classpath used for various build tasks.

There are 6 scopes available:

  • compile
    This is the default scope, used if none is specified. Compile dependencies are available in all classpaths of a project. Furthermore, those dependencies are propagated to dependent projects.
  • provided
    This is much like compile, but indicates you expect the JDK or a container to provide the dependency at runtime. For example, when building a web application for the Java Enterprise Edition, you would set the dependency on the Servlet API and related Java EE APIs to scope provided because the web container provides those classes. This scope is only available on the compilation and test classpath, and is not transitive.
  • runtime
    This scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath.
  • test
    This scope indicates that the dependency is not required for normal use of the application, and is only available for the test compilation and execution phases. This scope is not transitive.
  • system
    This scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository.
  • import (only available in Maven 2.0.9 or later)
    This scope is only supported on a dependency of type pom in the <dependencyManagement> section. It indicates the dependency to be replaced with the effective list of dependencies in the specified POM's <dependencyManagement> section. Since they are replaced, dependencies with a scope of import do not actually participate in limiting the transitivity of a dependency.

Each of the scopes (except for import) affects transitive dependencies in different ways, as is demonstrated in the table below. If a dependency is set to the scope in the left column, transitive dependencies of that dependency with the scope across the top row will result in a dependency in the main project with the scope listed at the intersection. If no scope is listed, it means the dependency will be omitted.

  compile provided runtime test
compile compile(*) - runtime -
provided provided - provided -
runtime runtime - runtime -
test test - test -

(*) Note: it is intended that this should be runtime scope instead, so that all compile dependencies must be explicitly listed - however, there is the case where the library you depend on extends a class from another library, forcing you to have available at compile time. For this reason, compile time dependencies remain as compile scope even when they are transitive.




评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值