身边有几位刚使用Maven的同学表示——在一个叫"pom.xml"的文件里声明一个依赖就不用去手动添加jar了,感觉这东西和自己手动管理依赖没太大区别。
当然,并不是这样,在此记录dependency那些事儿。

dependency

一个依赖可以按照maven的坐标标准进行定义。
比如:

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>

上面是最常见的坐标属性,偶尔也会看到有classifier
下面简单说明一下标签:

  • groupId:通常用作项目标识,比如SpringFramework项目的groupId是org.springframework。
    也可能会用作项目隶属的组织的名称,但组织下有多个项目则不好分辨,尽量保证层次级别明确。
  • artifactId:级别低于groupId的项目标识,通常用于标识一个module,比如spring-aop。
  • classifier:用于标识隶属于module的附件。
  • version:当前项目版本,版本的写法应有相应的规范。
  • type:依赖的类型,通常不需要声明,默认为jar。
  • scope:依赖范围,默认为compile。
  • packaging:打包方式,默认为jar。
  • optional:依赖是否可选。
  • exclusions:排除传递性依赖。

scope

引入Junit依赖时通常需要声明test scope:

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>

大概能猜出是测试时使用该依赖,但不完全正确。
Maven编译代码时需要使用classpath,但classpath不止一种,而是:

  • 编译classpath
  • 测试classpath
  • 运行classpath

Maven会根据需要使用不同的classpath,而scope可以用来控制依赖与这三种classpath之间的关系。

  • compile:默认使用该项,对三种classpath都有效。
  • test:仅对测试classpath有效,如上面的Junit。
  • provided:对编译和测试classpath有效,比如开头贴出的servlet-api的依赖,会在运行时由app server提供,Maven不可以重复引入。
  • runtime:对测试和运行classpath有效,编译时无效。
  • system:对编译和测试classpath有效,但必须通过systemPath显示指定依赖文件的位置,可以使用系统环境变量。
  • import:不针对任何一种classpath,该项用于导入其他pom中的dependencyManagement元素。

通常会使用前三种。
scope不仅用来控制依赖与classpath之间的关系,还会对依赖的传递性产生影响。
传递性依赖? 比如A依赖B,B依赖C,则A对于B是直接依赖,对于C是传递性依赖。
A对B、B对C的依赖范围决定了A对C的依赖范围。
如何决定? 下面给出一个关系表,垂直表示第一依赖,水平表示第二依赖,交叉单元格为传递性依赖。

  compile test provided runtime
compile compile     runtime
test test     test
provided provided   provided provided
runtime runtime     runtime

考虑一下这样的依赖关系,A-> C -> D(1.0)和A-> B -> D(2.0)
此时应该如何处理? 引入两种D依赖是不可能的。
Maven有依赖调节原则:

  • 路径最近优先。
  • 当路径长度相同,声明顺序优先。

对于上面的例子,A-> C -> D(1.0)和A-> B -> D(2.0)的路径长度相同,但前者声明早于后者,因此加入的传递性依赖则是D(1.0)。

另外,还需要考虑这样一个场景。
A依赖B、B依赖X和Y,X和Y都是可选依赖,即<optional>true</optional>,且4个都是compile。
此时,X和Y则不会被传递,对A是不可见的。

exclusions

但依赖调节并不解决所有问题,我们还需要exclusions来进行排除依赖
例如这样一个情况,工程中引入了A,A依赖B,但是B的版本过旧。
此时可以使用exclusions排除该传递性依赖,并显示声明一个最新版本的B依赖。
比如这样:

<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>4.2.1</version>
<exclusions>
<exclusion>
<artifactId>bcmail-jdk14</artifactId>
<groupId>bouncycastle</groupId>
</exclusion>
<exclusion>
<artifactId>bcprov-jdk14</artifactId>
<groupId>bouncycastle</groupId>
</exclusion>
<exclusion>
<artifactId>bctsp-jdk14</artifactId>
<groupId>bouncycastle</groupId>
</exclusion>
</exclusions>
</dependency>

properties

用于统一管理属性,比如我们引入很多spring framework:

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.0.3 RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.3 RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.0.3 RELEASE</version>
</dependency>

可见版本都是一样的,想更改版本时再一个一个修改太麻烦。

properties可以解决这一问题:

<properties>
<spring.version>4.0.3.RELEASE</spring.version>
</properties>

引入spring可以改为:

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>

这样确实简介了不少,但你可能仍然讨厌XML。

兴许,以后我们不会再用XML写构建文件。
我们可能会用一些插件(比如Polyglot for Maven)或者其他的什么东西(比如Gradle)。

repository

可以把Maven的仓库分为两种:

  • 本地仓库
  • 远程仓库

Maven寻找一个dependency时会先从本地仓库查找,如果找不到则在远程仓库查找,发现则下载到本地仓库使用。
如果都查找失败,会提示build failure。

或者,我们也可以把本地的jar放到本地仓库中:

mvn install:install-file -Dfile=jar包的路径 -DgroupId=我的groupId -DartifactId=我的artifactId -Dversion=我的version -Dpackaging=jar

本地仓库默认路径是用户目录下的.m2/repository/
该路径可以在settings.xml中修改,比如:

<localRepository>
/usr/local/maven/repository
</localRepository>

那么远程仓库又在哪里?
打开$M2_HOME/lib/maven-model-builder-3.2.1.jar里的
org/apache/maven/model/pom-4.0.0.xml

看到远程仓库的设置如下:

 <repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>http://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>

当然,我们也可以配置其他远程仓库,比如这样:

<repositories>
<repository>
<id>opensesame</id>
<name>Alibaba OpenSource Repsoitory</name>
<url>http://code.alibabatech.com/mvn/releases/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>

配置远程仓库时也需要注意一些选项

  • id:仓库的唯一标识符
  • name:仓库名称
  • url:仓库地址,通常都是http协议
  • layout:默认为default,表示仓库布局为maven2和maven3的布局
  • release/snapshots
    • enabled:是否支持发布版/快照版
    • updatePolicy:更新策略
      • 默认为daily
      • always : 每次构建时检查
      • never : 从不检查
      • interval : X:每隔X分钟间差
    • checksumPolicy:校验策略,默认为warn,另外有failignore

为什么区分release和snapshot? 不能只通过版本号进行区分吗?

试想一下这样的场景,假设有A和B两个模块,A依赖B,且B尚未开发完成。
如何让B模块每次更新后让A的开发人员获取?
每次更新后提示A的开发人员从VCS上pull下来构建?
或者不停地换版本号? 确实,就算B有了变化,但version也是依赖的标识之一。

如果依赖是snapshot则能解决这样的问题,snapshot发布时会加上一个时间戳,每次构建A的时候会检查B是否最新,间差更新策略就是上面的updatePolicy
另外,也可以执行mvn clean install-U强制更新。

远程仓库不都是想访问就访问的,有些仓库出于安全考虑,需要提供认证信息才可以访问。
认证必须在settings.xml中设置,下面是一个例子:

<servers>
<server>
<id>server001</id>
<username>my_login</username>
<password>my_password</password>
<privateKey>${user.home}/.ssh/id_dsa</privateKey>
<passphrase>some_passphrase</passphrase>
<filePermissions>664</filePermissions>
<directoryPermissions>775</directoryPermissions>
<configuration></configuration>
</server>
</servers>

Maven - dependency那些事儿的更多相关文章

  1. [Maven]Maven 那点事儿

    0. 前言 Jason Van Zyl,在 Java 十大风云人物排行榜上或许会看到他. 这兄弟是干嘛的? 他就是 Maven 的创始人,人们都尊称他为"Maven 他爸". 毋庸 ...

  2. Maven那点事儿(Eclipse版)

    Maven那点事儿(Eclipse版)   前言: 由于最近工作学习,总是能碰到Maven的源码.虽然平时工作并不使用Maven,但是为了学习一些源码,还是必须要了解下.这篇文章不是一个全面的Mave ...

  3. 【Java开发】Maven那点事儿(Eclipse版)

    Maven那点事儿(Eclipse版) 前言: 由于最近工作学习,总是能碰到Maven的源码.虽然平时工作并不使用Maven,但是为了学习一些源码,还是必须要了解下.这篇文章不是一个全面的Maven解 ...

  4. Maven错误Failed to read artifact descriptor for xxx:jar 和 missing artifact maven dependency

    可参考:http://stackoverflow.com/questions/6111408/maven2-missing-artifact-but-jars-are-in-place http:// ...

  5. lib目录和maven dependency目录的jar包冲突

    用eclipse时新建项目时,会在lib目录下自动生成一些jar包,然后又在pom.xml文件中添加了依赖,导致lib下的jar包和maven dependency目录下的jar包产生了冲突.刚开始r ...

  6. Maven 那点事儿(转)

    0. 前言 Jason Van Zyl,在 Java 十大风云人物排行榜上或许会看到他. 这兄弟是干嘛的? 他就是 Maven 的创始人,人们都尊称他为“Maven 他爸”. 毋庸置疑,Jason 也 ...

  7. Maven 那点事儿

    http://my.oschina.net/huangyong/blog/194583?fromerr=Dmf7HPwX Java那点事儿 Maven Smart 目录[-] 0. 前言 1. 安装 ...

  8. Maven Dependency Scope用法

    原帖地址:http://uule.iteye.com/blog/2087485 官方API描述 Dependency scope 是用来限制Dependency的作用范围的, 影响maven项目在各个 ...

  9. maven dependency的版本冲突问题

    在改造一个旧项目中,遇到各种问题. 旧项目有十多个模块,因为没有一个统一的父pom,它们对第三方的jar的版本没有统一. 虽然也存在公共的依赖模块,比如commons.util,但是,我们的模块中,有 ...

随机推荐

  1. bower报错:未能连接到github.com端口1080:超时和一些其他错误

    报错1:fatal: unable to access 'https://github.com/xxx/xxxx.git/': Failed to connect to github.com port ...

  2. LINQ to SQL语句大全

    LINQ to SQL语句大全     LINQ to SQL语句(1)之Where 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判 ...

  3. Java基础学习篇---------继承

    一.覆写(重写) 1.含义:子类的定义方法.属性和父类的定义方法.属性相同时候 方法名称相同,参数相同以及参数的个数也相同,此时为覆写(重写) 扩充知识点: 覆盖:只有属性名字和方法名字相同,类型.个 ...

  4. python 利用from ... import * 的特性实现文件的覆盖

    在Python中, 如果使用 from module import * 这样方式进行导包, 就会把module模块里所有的变量导入进来, 并且可以直接使用(其实导包时 module 模块已经被从头到尾 ...

  5. ssh密钥认证排错

    sshd配置文件没问题: 目录权限设置也没问题: 但是 ssh -vvv 提示: debug3: no such identity: /Users/user/.ssh/id_rsa,/Users/us ...

  6. POJ 2393

    #include <iostream> #include <algorithm> using namespace std; int main() { //freopen(&qu ...

  7. 移动端h5直播项目|html5直播实战开发|h5仿陌陌

    最近一些直播.小视频什么的都比较火,像陌陌.抖音.火山短视频… 于是空闲时间自己也利用html5技术也试着倒腾了下直播项目,使用到了h5+css3+iscroll+zepot+swiper+wlsPo ...

  8. activiti插件安装-离线安装

    直接选择离线安装,在线因为网络问题,一直提示失败. 一.下载插件Activiti BPMN 2.0 designer 链接: https://pan.baidu.com/s/1gKBHZFnmNJx7 ...

  9. 剑指offer四十四之翻转单词顺序列

    一.题目 牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上.同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思.例如,“student ...

  10. 剑指offer三十九之平衡二叉树

    一.题目 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 二.思路 详解代码. 三.代码 public class Solution {     //判断根节点左右子树的深度,高度差超过1,则不平衡 ...