使用maven构建多模块项目。在一个项目中使用多个模块的一个方法是将模块添加为依赖项,正常情况下,我们会添加一个外部模块作为依赖。但是,当模块是一个项目的一部分,并密切相关的时候,该项目应被构造为一个多模块项目。在一个多模块项目中,Maven可以确保所有子模块在主模块之前被构建。
我们的实例简单易懂:将一个获取指定格式的当前时间的方法拆分成两个子模块:app和util。util提供一个使用apache commons lang库格式化日期的静态方法,app模块依赖util模块打印格式化的日期。
首先,使用如下命令创建工程和模块目录:
-- create directory for top level project
$ mkdir multi-app
-- create directories for modules
$ cd multi-app
$ mkdir app
$ mkdir util
-- create source and test dir for util module
$ mkdir -p util/src/main/java/com/xyz/util
$ mkdir -p util/src/test/java/com/xyz/util
-- create source dir for app module
$ mkdir -p app/src/main/java/com/xyz
multi-app
目录作为多模块项目的顶层目录,它包含两个子模块:app
和util
。
多模块项目的顶层目录中需要包含一个pom.xml,multi-app/pom.xml:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- project coordinates项目坐标 -->
<groupId>com.xyz</groupId>
<artifactId>multi-app</artifactId>
<version>1.0</version>
<!--多模块项目的顶层目录的pom.xml打包类型必须为pom-->
<packaging>pom</packaging>
<!--包含两个子模块-->
<modules>
<module>app</module>
<module>util</module>
</modules>
</project>
在顶层POM中,我们定义了多模块项目的坐标和它的模块。顶层项目目录中仅仅包含一个pom.xml,并且打包类型为pom。modules/module
元素中,给多模块项目添加了两个子模块。顶层项目是父项目,它的坐标被正如我们接下来看到的,将会在子模块中引用。
你可能已经注意到了,在上面的模块定义中,我们将util放在app模块之后,但实际上util模块必须在app模块之前构建,因为app依赖于它。而在父模块(顶层模块)的pom.xml定义中使我们感到困惑的子模块构建顺序实际上会被mavan的一个反应堆(reactor)组件根据子模块的依赖合理安排它们的构建顺序。当我们构建multi-app时,reactor会先构建util再构建app。
util模块只有一个简单个DateUtil 类提供了一个静态发方法getToday()用来返回一个格式化的日期,也包含了一个测试方法。
multi-app/util/src/main/java/com/xyz/util/DateUtil.java
:
package com.xyz.util;
import java.util.Date;
import org.apache.commons.lang.time.DateFormatUtils;
public class DateUtil {
public static String getToday() {
String today = DateFormatUtils.format(new Date(), "dd-MMM-yyyy");
return today;
}
}
multi-app/util/src/test/java/com/xyz/util/DateUtilTest.java
:
package com.xyz.util;
import static org.junit.Assert.assertEquals;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.junit.Test;
public class DateUtilTest {
@Test
public void testGetToday() {
String actual = DateUtil.getToday();
String expected = new SimpleDateFormat("dd-MMM-yyyy")
.format(new Date());
assertEquals(expected, actual);
}
}
util模块的pom.xml
定义了该模块的坐标和依赖,另外还使用了parent
元素包含了multi-app的坐标。
multi-app/util/pom.xml
:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- parent coordinates父模块坐标 -->
<parent>
<groupId>com.xyz</groupId>
<artifactId>multi-app</artifactId>
<version>1.0</version>
</parent>
<!-- project coordinates -->
<groupId>com.xyz</groupId>
<artifactId>util</artifactId>
<version>1.0</version>
<!-- project dependencies -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
</project>
app模块仅仅包含一个App.java类依赖util模块输出格式化的日期。
multi-app/app/src/main/java/com/xyz/App.java
:
package com.xyz;
import com.xyz.util.*;
public class App {
public static void main(String[] args) {
System.out.println("Hello World! Today is " + DateUtil.getToday());
}
}
app模块的pom.xml定义了该模块的坐标,并且依赖了util模块,同样的将multi-app模块作为父模块。
multi-app/app/pom.xml
:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- parent coordinates -->
<parent>
<groupId>com.xyz</groupId>
<artifactId>multi-app</artifactId>
<version>1.0</version>
</parent>
<!-- project coordinates -->
<groupId>com.xyz</groupId>
<artifactId>app</artifactId>
<version>1.0</version>
<!-- project dependencies -->
<dependencies>
<dependency>
<groupId>com.xyz</groupId>
<artifactId>util</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
至此整个项目结构如下所示:
构建maven多模块项目,我们需要在顶层目录中运行build命令。可以这样构建 multi-app:
$ cd multi-app
$ mvn test
maven处理顶层POM文件multi-app/pom.xml
,它知道如何处理子模块 的POM文件app/pom.xml
和util/pom.xml
。一旦POM被处理,根据使用的模块反应堆构reactor建建立顺序依赖性并构建各模块。上述命令,maven首先执行multi-app的测试阶段(但是发现顶层项目并没有任何源码,不做任何事情)然后编译和测试util模块,最后编译和测试app模块。
对于mvn clean
命令,会按multi-app、util和app模块的顺序clean。
mvn install
命令编译、测试、打包、安装( compiles, tests, packages and installs)顺序是:multi-app、util 和app。
Assembly插件目的是提供一个把工程依赖元素、模块、网站文档等其他文件存放到单个归档文件里。 使用任何一个预定义的描述符你可以轻松的构建一个发布包。 而Maven多模块项目构建命令被执行,通常情况下,从项目的顶层目录开始,但是assembly 命令稍有不同。
在项目的顶层目录运行命令 assembly:assembly:
$ mvn assembly:assembly -DdescriptorId=project
为预先定义的描述符的src和bin,运行组件:组件的子模块的目录:
$ cd app
$ mvn assembly:assembly -DdescriptorId=src
$ cd ../util
$ mvn assembly:assembly -DdescriptorId=src
对于预定义描述符jar-with-dependencies,同样在app目录下执行assembly:assembly命令:
$ cd app
$ mvn assembly:assembly -DdescriptorId=jar-with-dependencies
POM中的pluginManagement元素允许在父POM中进行配置,所有子模块均可以继承这些配置。
假设multi-app的所有子模块均使用jdk1.8,一种方式是在app、util模块中的POM均配置编译插件。但是更好的方式是在顶层父模块中使用pluginManagement
元素,从而所有子模块均可继承插件配置。
multi-app/pom.xml
:
...
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
...
当plugins/plugin元素直接在buile元素中使用的时候,插件定义会在当前POM生效。但是如果plugins/plugin元素是在pluginManagement元素中时,当前使用这种定义的POM位置并不会使用它,但是可以被子模块来继承配置生效。因此,multi-app的POM并不会使用maven-compiler-plugin插件指定的配置,而是会被app、util两个子模块继承使用。
戳这里下载项目源码: http://download.csdn.net/detail/zixiao217/9689359