我们来回顾一下,我们在开发项目时,一个大的项目往往会拆分成多个工程,比如,电商网站,可能会分成base、core等模块,每个模块都是一个工程,然后不同的业务,比如product、order等业务模块,也会单独成一个工程,那么工程与工程之间就必然有关联,比如,order模块依赖core模块。以往我们没有使用maven时,我么往往会借助工具,比如eclipse中可以build path中添加project关联
但是在执行单元测试、打包之类的操作时,我们还是得针对每个工程操作。工程比较少的时候,我们还可以手工操作,但是工程一旦多起来,将会显得很繁琐。
maven天然就是支持多模块的。maven通过聚合的方式,将项目的各个模块聚合在一起,当我们针对聚工程块执行构建时,聚合工程包含的模块也会执行相应的构建动作。
聚合
使用聚合,我们一般会单独建立一个maven工程。这个工程没有任何业务,仅仅是用于聚合作用,因此,它仅需在工程根目录下有一个pom.xml文件就可以了。pom的内容如下:
聚合工程的pom内容与普通工程的pom文件没有太大差异,除了packaging为pom例外。另外,我们需要通过modules及其子元素module指定聚合的子模块。这样,我们在针对聚合模块执行构建过程时,其包含的子模块也会依次执行相应的构建动作,不需要单独针对每个模块执行构建动作。
继承
思考这样一个问题,我们有一个项目,它分成了多个模块,core、base、web、product、order等,可能我们的core模块用到了spring的依赖,我们的web、order也用到了spring的依赖,这样,我们需要在core、web、order各自工程的pom文件中加入spring的依赖配置。如果使用的第三方依赖不多,这样做倒还可以接受,但是我们往往会依赖很多第三方jar,这样就会形成很多重复配置。
maven通过继承的方式,消除pom的重复配置。这有点类似java中的继承。公共的操作放在父类中,子类继承后就自动拥有相应的功能。
要配置继承,我们也需要定义一个单独的父工程,让子工程继承。为了减少工程,我们可以把父工程和聚合工程合并。我们把需要的依赖都通过dependency元素,配置在聚合工程中,然后在子工程中指定父工程为聚合工程:
子工程中通过parent元素,指定父工程的GAV及相对位置,这样,配置在父工程中的依赖,子工程中无需在配置依赖了。
以下是maven中的可被继承的pom元素:
- groupId:项目组id
- version:项目版本
- description:项目描述
- organization:项目的组织信息
- inceptionYear:项目创始年份
- url:项目URL地址
- developers:开发者信息
- contributors:贡献者信息
- distributionManagement:部署配置
- issueManagement:缺陷跟踪系统信息
- ciManagement:持续集成系统信息
- scm:版本控制系统信息
- mailingLists:邮件列表信息
- properties:自定义maven属性
- dependencies:依赖配置
- dependencyManagement:依赖配置管理
- repositories:仓库配置
- build:包括项目的源码目录配置、输出目录配置、插件配置等
- reporting:项目的报告输出目录配置、报告插件配置等
依赖管理
我们再来思考这样一个问题,通过继承的方式,的确是减少了重复依赖的配置,所以,我们把所有的依赖配置都配置在父模块中,子模块继承之后,就不需要再配置任何依赖了。这样的话,往往会引入一些不需要的依赖。比如,core模块中使用了hibernate的jar,我们把这个依赖配置到父模块中,core继承了父模块,那么core中自动引入了hibernate的jar,我们的web也继承了父模块,web模块也会自动引入hibernate的jar,而web是不需要hibernate的jar的。对于这种情况,maven使用dependencyManagement元素来管理依赖。dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证子模块依赖使用的灵活性。
我们在父模块的dependencies元素之外,使用dependencyManagement元素包裹,这样,父模块中的这些依赖配置仅仅是一个定义,不会真正引入相应的依赖。子模块在继承父模块之后,也不会直接引入相应的依赖,需要在子模块中显示配置依赖,因为这时候依赖已经在父模块中定义了,所以子模块中的依赖仅需配置groupId和artifactId即可,无需配置version。
除了dependencyManagement元素用于依赖的管理之外,还有pluginManagement元素用于管理插件依赖。
属性定义
考虑这样一种情况,很多项目会使用spring,但是spring的模块有很多,我们一般会统一使用同一个版本的模块,比如3.2.5-RELEASE,那么我们在配置依赖时,每个依赖都指定version为3.2.5-RELEASE。但是有一天,我们不得不升级spring的版本时,我们就需要修改每个依赖的version,将其改为新的版本。同意版本的依赖比较少的时候,我们可以这么做,但是一旦数量多了,手工操作就麻烦了,甚至有时候忘了将某个依赖的版本修改,导致版本不一致。对于这种情况,我们可以使用属性替换的方式。
在pom中,通过properties元素下定义依赖的版本,在dependency中使用$操作引用定义的版本,以后修改版本,只需修改properties中定义的版本即可。