Maven实战:pom.xml与settings.xml

義往昔 1月前 ⋅ 35 阅读

http://www.importnew.com/22779.html

pom.xml与settings.xml

pom.xml与setting.xml,可以说是Maven中最重要的两个配置文件,决定了Maven的核心功能,虽然之前的文章零零碎碎有提到过pom.xml和settings.xml里面的内容,但都是大略带过,学习与研究地并不细致,本文的目的就是详细研究下这两个Maven重要的配置文件,从这两个配置文件可以牵出非常多的Maven话题。

Maven坐标

首先谈一下为什么要使用Maven坐标。

Maven世界拥有数量非常巨大的构件,也就是平时使用的一些jar、war等文件,在Maven为这些构件引入坐标概念之前,我们无法使用任何一种方式来唯一标识所有这些构件。因此,如果需要使用Spring依赖,那么就去Spring官网寻找;如果需要使用log4j依赖,那么又去Apache官网寻找。又因为各个网站风格迥异,大量时间花费在了搜索和浏览网页的工作上。没有统一规范与法则,工作就无法自动化,重复性的劳动本来就应该交给机器来做

Maven定义了这样一组规则:世界上任何一个构件都可以使用Maven坐标唯一标识,Maven坐标元素包括groupId、artifactId、version、packaging、classifier,现在只要我们提供正确的元素坐标,Maven就能找到对应的构件。至于去哪里下载,Maven本身内置了一个中央仓库的地址”http://repo1.maven.org/maven2″,该中央仓库包含了世界上绝大部分流行的开源项目构件,Mavne会在需要的时候去那里下载,当然也可以配置自己的中央仓库地址,去自己的中央仓库下载构件。

举个例子,Spring的context:

1
2
3
4
5
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.2.6.RELEASE</version>
</dependency>

看一下下属的各个元素:

  • groupId:定义当前Maven项目隶属的实际项目。由于Maven项目和实际项目未必是一对一的关系,比如SpringFramework这个实际项目可能对应的Maven项目有很多,像core、context、expression等等,因此groupId不应该对应项目隶属的公司或组织,否则artifact将很难定义
  • artifactId:定义实际项目中的一个Maven模块,推荐的做法是使用实际项目名称作为artifactId的前缀,这样会很方便去寻找实际构件
  • version:定义Maven项目当前所处的版本,如上面的spring-context就是4.2.6的,RELEASE表示正式发行版本
  • packing:定义Maven项目的打包方式,这项不是必须的,没列出来,不定义默认就是jar的打包方式
  • classifier:帮助定义构件输出的一些附属构件,比如xxx-javadoc.jar、xxx-sources.jar,附属构件与主构件对应,这项是不能直接定义的

Maven坐标的概念大致上就是这样,理解Maven坐标,是理解Maven很重要的一步。

传递性依赖

什么是传递性依赖,以Spring举一个例子。使用Spring的时候会依赖于其他开源的类库,此时有两种做法:

1、下载一个很大的.zip包,里面包含了所有Spring的jar,但是这么做往往就引入了许多不必要的依赖

2、只下载spring相关的.zip包,不包含依赖,实际使用的时候根据出错信息,加入需要的其他依赖

显然这两种做法都非常麻烦,Maven的传递性依赖机制很好地解决了这一问题。打开spring-core-4.1.0.RELEASE的pom.xml,我截取一段关键部分:

<dependencies>
    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
      <version>1.9</version>
      <scope>compile</scope>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.1.3</version>
      <scope>compile</scope>
    </dependency>
    ...
</dependencies>

比如A项目依赖了spring-core,spring-core又依赖了commons-codec和commons-logging,那么commons-codec和commons-logging就是A项目的一个传递性依赖。有了传递性依赖机制,在使用spring-core的时候就不用去考虑它依赖了什么,也不用担心引入多余的依赖,Maven会解析各个直接依赖的POM,将那些必要的间接依赖,以传递性依赖的形式引入到当前的项目中去。

有了传递性依赖机制,一方面大大简化和方便了依赖声明,另一方面在大部分情况下我们只需要关心项目的直接依赖是什么而不用考虑这些直接依赖会引入什么传递性依赖,不过有时候传递性依赖也会有一些问题,此时我们就需要清除地知道该传递性依赖是从哪条路径引入的,这就叫依赖调解,依赖调解主要有两点原则:

1、A->B->C->X(1.0),A->D->X(2.0),此时两条依赖路径上有两个版本的X,此时遵循路径最近者优先,因此X(2.0)将被解析使用

2、A->B->Y(1.0),A->C->Y(2.0),Y(1.0)和Y(2.0)的依赖长度是一样的,从Maven2.0.9开始,此时遵循第一声明者优先,即顺序最靠前的那个依赖优先

排除依赖

传递性依赖会给项目隐式地引入很多依赖,这极大地简化了项目依赖的管理,但是有时候这种特性也会带来问题。比如有种情况:

当前项目依赖A,A由于某些原因依赖了另外一个类库的SNAPSHOT版本,那么这个SNAPSHOT就会成为当前项目的传递性依赖,二SNAPSHOT的不稳定性将直接影响到当前的项目,此时就需要排除该SNAPSHOT,并且在当前项目中声明该类库的某个正式发布的版本

 

排除依赖很简单,看一下写法:

<dependency>
    <groupId>com.alibaba.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>3.2.7</version>
    <exclusions>
        <exclusion>
            <groupId>apache-lang</groupId>
            <artifactId>commons-lang</artifactId>
        </exclusion>
    </exclusions>
</dependency>

这里我引入了rocketmq的依赖,但是我不想依赖rocketmq里面的apache-lang,而想要自己引入依赖,所以我就把apache-lang给排除了。

这里需要注意的是,声明exclusion的时候只需要groupId和artifactId即可,而不需要version元素,这是因为只需要groupId和artifactId就能唯一定位依赖图中的某个依赖。换句话说,Maven解析后的依赖中,不可能出现groupId和artifactId相同,但是version不同的两个依赖。

settings.xml

settings.xml里面是Maven的基本配置,元素比较多,逐一看一下..后续原文:

http://www.importnew.com/22779.html

 


注意:本文归作者所有,未经作者允许,不得转载

全部评论: 0

    我有话说: