Maven入门实战笔记06-聚合与继承

目录一览:

聚合

继承

可继承的POM元素

依赖管理

插件管理

聚合与继承

约定优于配置

反应堆

 

 

 

聚合与继承概述:

Maven的聚合特性能够把各项目的各个模块聚合在一起构建;

Maven的继承特性能帮助抽取各模块相同的依赖和插件等配置,在简化POM的同时,还能促进各个模块配置的一致性。

-------------------------------------------------------

用到的项目  《Maven实战》(许晓斌 著) 一书中的一个用户登录注册的项目

-------------------------------------------------------

项目简介:用户注册服务,分为以下5个模块

account-web:包含与web相关的内容

account-service:系统核心,封装下层细节,对外暴露接口,Facade模式

account-persist:处理帐户信息持久化

account-captcha:处理验证码的key、图片的生成以及验证等

account-email:处理邮件服务的配置、激活邮件的编写和发送

-------------------------------------------------------

 

聚合

需求:一次构建这一个模块

创建一个account-aggregator的模块,然后通过该模块构建整个项目的所有模块

account-aggregator作为一个Maven项目,有自己的POM,同时也作为一个聚合项目

其pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.juvenxu.mvnbook.account</groupId>
	<artifactId>account-aggregator</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>Account Aggregator</name>

	<modules>
		<module>account-email</module>
		<module>account-persist</module>
		<module>account-captcha</module>
		<module>account-service</module>
		<module>account-web</module>
	</modules>
</project>

name字段是为了给项目提供一个更容易阅读的名字

 

packaging对应默认值为jar,对于聚合模块来说,其打包方式packaging的值必须为pom,否则无法构建。

moudles元素,实现聚合的核心配置

每个moudle的值都是一个当前POM的相对目录,如:

account-aggregator的pom.xml的路径为:

D:/WorkStation/maven/account-aggregator/pom.xml,

那么其它模块如account-web就对应了目录:

D:/WorkStation/maven/account-aggregator/account-web

一般,为快速定位内容,模块所处的目录名称应当与其artifactId一致(推荐非必须)

为方便用户构建项目,通常将聚合模块放在项目目录的最顶层,其它模块则作为聚合模块的子目录存在

聚合模块仅仅是帮助聚合其他模块的工具,它本身并无实质内容,因此聚合模块的内容仅是一个pom.xml文件

以上配置是聚合模块的父子目录结构:

 

account-aggregator
--pom.xml
--account-email
----src
----pom.xml
--account-persist
----src
----pom.xml

 对moudles作如下配置:

 

 

<modules>
	<module>../account-email</module>
	<module>../account-persist</module>
	<module>../account-captcha</module>
	<module>../account-service</module>
	<module>../account-web</module>
</modules>

 则对应聚合模块的平行目录结构:

account-aggregator
--pom.xml
account-email
--src
--pom.xml
account-persist
--src
--pom.xml

 

 

测试接口而不测试实现原则,测试代码不能引用实现类

 

继承

Maven的聚合特性可以通过一条命令同时构建N个模块,解决了多模块Maven项目的一个问题

问题:相同的配置、依赖。。。

POM的继承:通过继承机制抽取重复配置

一处声明多处使用

Java中,创建类的父子结构:父类中声明字段方法供子类POM继承

Maven中,创建POM的父子结构:父POM中声明一些配置供子POM继承

项目实例:

创建一个父模块account-parent,

在account-aggregator下创建一个名为account-parent的子目录,在该子目录下建立一个所有除account-aggregator之外的父模块,其pom.xml配置如下:

 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.juvenxu.mvnbook.account</groupId>
	<artifactId>account-parent</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>Maven Account-Parent Project</name>

	<modules>
		<module>account-email</module>
		<module>account-persist</module>
		<module>account-captcha</module>
		<module>account-service</module>
		<module>account-web</module>
	</modules>
</project>

 注意:artifactId为account-parent,表示这是一个父模块

 

packaging为pom,作为父模块的POM,其打包类型也必须为pom

由于父模块只是为了帮助消除配置的重复,因此它本身不包含除POM之外的项目文件

其它模块来继承它,如account-email的POM(部分)如下:

 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>com.juvenxu.mvnbook.account</groupId>
		<artifactId>account-parent</artifactId>
		<version>1.0.0-SNAPSHOT</version>
                <relativePath>../account-parent/pom.xml</relativePath>
	</parent>

	<artifactId>account-email</artifactId>
	<name>Maven Account-Email Project</name>

	<dependencies>
		。。。
	</dependencies>

	<build>
		<plugins>
			。。。
		</plugins>
	</build>
</project>

 parent元素声明父模块,其下的groupId、artifactId和version指定了你模块的坐标,这三个元素必须的

relativePath元素表示你模块POM的相对路径,上述配置中的../account-parent/pom.xml表示父POM的位置在与account-email目录平行的account-parent目录下

 

account-aggregator
--pom.xml
--account-parent
----pom.xml
--account-email
----src
----pom.xml
--account-persist
----src
----pom.xml

 

 

relativePath的默认值是../pom.xml,也就是说,Maven默认父POM在上一层目录下

 

正确设置relativePath很重要,因为相互具有继承关系

 

 

account-aggregator
--pom.xml
account-parent
--pom.xml
account-email
--src
--pom.xml
account-persist
--src
--pom.xml

对于artifactId元素,子模块应该显式声明,一方面,如果完全继承groupId、artifactId和version,会造成坐标冲突,另一方面,好使使用不同的groupId或version,同样的artifactId容易造成混淆

 

最后将父模块account-parent加入到聚合模块account-aggregator中,在聚合模块中的pom.xml中加入

 

<module>account-parent</module>

 

总结:

1.聚合可以方便快速构建项目

2.继承可以避免重复配置

 

可继承的POM元素

groupId和version是可以被继承的,可以被继承的POM元素如下:

groupId

version

description

organization

inceptionYear

url

developers

contributors

distributionManagement:项目的部署配置

issueMagement

ciManagement

scm

mailingLists

properties

dependencies:项目的依赖配置

dependencyManagement

repositories

build:包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等

reporting

依赖管理

依赖是会被继承的

Maven提供的dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证子模块依赖使用的灵活性

在dependencyManagement元素下的依赖声明不会引入实际的依赖,不过它能够约束dependencies下的依赖使用,如在account-parent中加入dependencyManagement配置

 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.juvenxu.mvnbook.account</groupId>
	<artifactId>account-parent</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>Maven Account-Parent Project</name>

	<modules>
		<module>account-email</module>
		<module>account-persist</module>
		<module>account-captcha</module>
		<module>account-service</module>
		<module>account-web</module>
	</modules>

	<!-- Maven属性 -->
	<properties>
		<project.build.sourceEncoding>
			UTF-8
		</project.build.sourceEncoding>
		<project.reporting.outputEncoding>
			UTF-8
		</project.reporting.outputEncoding>
		<project.version>1.0.0-SNAPSHOT</project.version>
		<springframework.version>2.5.6</springframework.version>
		<junit.version>4.10</junit.version>
	</properties>

	<!-- 依赖 -->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-core</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-beans</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context-support</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>junit</groupId>
				<artifactId>junit</artifactId>
				<version>${junit.version}</version>
				<scope>test</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
</project>

 这里使用dependencyManagement声明的依赖既不会给account-parent引入依赖,也不会给它的子模块引入依赖,不过这段配置是会被继承的。修改account-email的POM如下:

 

 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>com.juvenxu.mvnbook.account</groupId>
		<artifactId>account-parent</artifactId>
		<version>1.0.0-SNAPSHOT</version>
	</parent>

	<artifactId>account-email</artifactId>
	<name>Maven Account-Email Project</name>

	<properties>
		<javax.mail.version>1.4.1</javax.mail.version>
		<greenmail.version>1.3.1b</greenmail.version>
	</properties>

	<!-- 依赖 -->
	<dependencies>
		<!-- 继承父pom -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</dependency>
		
		<!--  -->
		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
			<version>${javax.mail.version}</version>
		</dependency>
		<!-- 邮件服务测试 -->
		<dependency>
			<groupId>com.icegreen</groupId>
			<artifactId>greenmail</artifactId>
			<version>${greenmail.version}</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
</project>

 这种依赖管理机制似乎不能减少太多POM配置,不过推荐这样做,原因保持版本一致,降低依赖冲突的机率

 

如果子模块不声明依赖的使用,即使该依赖已经在父POM的dependencyManagement中声明了,也不会产生任何实际的效果

import依赖范围:该范围的依赖只在dependencyManagement元素下才有效果,使用该范围的依赖通常指向一个POM,作用是将目标POM中的dependencyManagement配置导入并合并到当前POM的dependencyManagement配置,除了复制配置或者继承这两种方式外,还可以使用import范围依赖将这一配置导入,如:

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>com.juvenxu.mvnbook.account</groupId>
			<artifactId>account-parent</artifactId>
			<version>1.0-SNAPSHOT</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

 上述代码中依赖的type为pom,import范围依赖由于其特殊性,一般都是指向打包类型为pom的模块

 

如果有多个项目,它们使用的依赖版本都是一致的,则就可以定义一个使用dependencyManagement专门管理依赖的POM,然后在各个项目中导入这些依赖管理配置。

 

 

插件管理

Maven提供了pluginManagement元素管理插件,该元素中配置的依赖不会造成实际的插件调用行为,当POM中配置了真正的plugin元素,并且其groupId和artifactId与pluginManagement中配置的插件匹配时,pluginManagement的配置都会影响实际的插件行为

如:在父POM中配置pluginManagement

<build>
	<!-- 插件 -->
	<pluginManagement>
		<plugins>
			<!-- 支持java 5 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>
			<!-- 使用UTF-8编码处理资源文件 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-resources-plugin</artifactId>
				<version>2.5</version>
				<configuration>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
		</plugins>
	</pluginManagement>
</build>

 

继承了pluginManagement后的插件配置

 

<build>
	<plugins>
		<!-- 继承父pom -->
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
		</plugin>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-resources-plugin</artifactId>
		</plugin>
	</plugins>
</build>

 当项目中的多个模块有同样的插件配置时,应当将配置移到父POM的pluginManagement元素中

统一项目的插件版本,避免潜在的插件不一致或者不稳定问题,也更易于维护

 

聚合与继承

概述

聚合主要是为了方便快速构建项目

继承主要是为了消除重复配置

不同

对于聚合来说,它知道有哪些被聚合的模块,但那些被聚合的模块不知道这个聚合模块的存在

对于继承关系的父POM来说,它不知道有哪些子模块继承于它,但那些子模块都必须知道自己的父POM是什么

共同

(1)聚合POM与继承关系的父POM的packaging都必须是pom;

(2)聚合模块与继承关系中的父模块除了POM之外都没有实际的内容

合并聚合和继承功能后的account-parent的POM配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.juvenxu.mvnbook.account</groupId>
	<artifactId>account-parent</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>Maven Account-Parent Project</name>

	<modules>
		<module>account-email</module>
		<module>account-persist</module>
		<module>account-captcha</module>
		<module>account-service</module>
		<module>account-web</module>
	</modules>

	<!-- Maven属性 -->
	<properties>
		<project.build.sourceEncoding>
			UTF-8
		</project.build.sourceEncoding>
		<project.reporting.outputEncoding>
			UTF-8
		</project.reporting.outputEncoding>
		<project.version>1.0.0-SNAPSHOT</project.version>
		<springframework.version>2.5.6</springframework.version>
		<junit.version>4.10</junit.version>
	</properties>

	<!-- 依赖 -->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-core</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-beans</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context-support</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>junit</groupId>
				<artifactId>junit</artifactId>
				<version>${junit.version}</version>
				<scope>test</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<build>
		<!-- 插件 -->
		<pluginManagement>
			<plugins>
				<!-- 支持java 5 -->
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<version>2.3.2</version>
					<configuration>
						<source>1.5</source>
						<target>1.5</target>
					</configuration>
				</plugin>
				<!-- 使用UTF-8编码处理资源文件 -->
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-resources-plugin</artifactId>
					<version>2.5</version>
					<configuration>
						<encoding>UTF-8</encoding>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>
</project>

 相应子模块的POM配置也做微小修改,本来父模块与子模块位于同级目录,现在新的account-parent在上一层目录 ,这是Maven默认能识别的父模块位置,因此无须再配置relativePath,如:

。。。
	<parent>
		<groupId>com.juvenxu.mvnbook.account</groupId>
		<artifactId>account-parent</artifactId>
		<version>1.0.0-SNAPSHOT</version>
	</parent>
。。。

 

 

约定优于配置

 约定优于配置,Maven核心设计理念之一

使用约定可以大量减少配置

超级POM

Maven3:%M2_HOME%/lib/maven-model-builder-x.x.x.jar中

org/apache/maven/model/pom-4.0.0.xml

Maven2:%M2_HOME%/lib/maven-x.x.x-uber.jar中

org/apache/maven/project/pom-4.0.0.xml

任何一个Maven项目都隐式地继承自超级POM

大量超级POM的配置都会被 所有Maven继承,这些配置也就成为了Maven所提倡的约定

 

反应堆

在一个多模块的Maven项目中,反应堆(Reactor)是指所有模块组成的一个构建结构。

对于单模块的项目,反应堆就是该模块本身,但对于多模块项目来说,反应堆就包含了各模块之间继承与依赖的关系,从而能够自动计算出合理的模块构建顺序。

反应堆的构建顺序

Maven按序读取POM,如果该POM没有依赖模块,那么就构建该模块,否则就先构建其依赖模块,如果该依赖还依赖于其他模块,则进一步先构建依赖的依赖。

类似于递归

裁减反应堆

需求:

用户会选择构建整个项目或者选择构建单个模块,但有时,用户仅需构建完整反应堆中的某些个模块,换句话说,用户需要实时地裁减反应堆

命令:

-am, --also-make:同时构建所列模块的依赖模块

-amd, -also-make-dependents:同时构建依赖于所列模块的模块

-pl, --projects <arg>:构建指定的模块,模块间用逗号分隔

-rf, -resume-from <arg>:从指定的模块回复反应堆

 

 

mvn clean install

得到完整反应堆
Maven入门实战笔记06-聚合与继承
 

mvn clean install -pl account-email,account-persist

 指定构建某几个模块
Maven入门实战笔记06-聚合与继承
 

mvn clean install -pl account-email -am

 同时构建所列模块的依赖模块
Maven入门实战笔记06-聚合与继承
 

mvn clean install -pl account-parent -amd

 同时构建依赖于所列模块的模块

 

mvn clean install -rf account-email

 可以在完整的反应堆构建顺序基础上指定从哪个模块开始构建
Maven入门实战笔记06-聚合与继承
 

mvn clean install -pl account-parent -amd -rf account-email

 对裁剪后的反应堆再次裁剪

--------------------------------------------------------------------------------------------------------------------

@author Free Coding http://ln-ydc.iteye.com/

你可能感兴趣的:(maven)