maven 多模块管理

一、项目结构如下

maven-multi-module
`------ core
          `--- pom.xml

`------ webapp
         `--- pom.xml

`------ pom.xml

说明:

  • 最外层是一个叫“maven-multi-module”的工程,里面有一个 pom.xml 和 两个子工程“core”和“webapp”。
  • “core”是在“maven-multi-module”的工程内部的一个工程,有一个 pom.xml。
  • “webapp”也是在“maven-multi-module”的工程内部的一个工程,有一个 pom.xml。webapp 依赖 core 工程

二、关于模块

(1) 模块的概念

在 maven-multi-module 工程的 pom.xml 中,有下面的代码的话,代表 core 和 webapp 是两个模块。

<modules>
  <module>core</module>
  <module>webapp</module>
</modules>

(2) 模块的好处

1),关于“mvn clean install”

此时再在maven-multi-module目录下执行 “mvn clean install”,Maven将根据自己的Reactor机制决定哪个模块应该先执行,哪个模块应该后执行。比如,这里的webapp模块依赖于core模块,那么Maven会先在core模块上执行“mvn clean install”,再在webapp模块上执行相同的命令。在webapp上执行“mvn clean install”时,由于core模块已经被安装到了本地的Repository中,webapp便可以顺利地找到所依赖的core模块。

总的来看,此时命令的执行顺序为maven-multi-module -> core -> webapp,先在maven-multi-module上执行是因为其他两个模块都将它作为父模块(这里是父模块,并不是继承的关系),即对它存在依赖关系,又由于core被webapp依赖,所以接下来在core上执行命令,最后在webapp上执行。

2),是不是必须得在maven-multi-module目录下执行 “mvn clean install”

并不是非得如此,只是你需要搞清楚Maven的工作机制。在maven-multi-module目录下执行,即是在父工程中执行,此时Maven知道父模块所包含的所有子模块,并会自动按照模块依赖关系处理执行顺序。如果只在子模块中执行,那么Maven并不知道它对其他模块的依赖关系。举个例子,当在webapp中执行 “mvn clean install”,Maven发现webapp自己依赖于core,此时Maven会在本地的Repository中去找core,如果存在,那么你很幸运,如果不存在,那么对不起,运行失败,说找不到core,因为Maven并不会先将core模块安装到本地Repository。此时你需要做的是,切换到core目录,执行“mvn clean install”将core模块安装到本地Repository,再切换回webapp目录,执行“mvn clean install”,万事才大吉。

多么繁琐的步骤,此时你应该能体会到在maven-multi-module下执行Maven命令的好处了吧。总结一下:在maven-multi-module下执行“mvn clean install”, Maven会在每个模块上执行该命令,然后又发现webapp依赖于core,此时他们之间有一个协调者(即父工程),它知道将core作为webapp的依赖,于是会先在core模块上执行“mvn clean install”,当在webapp上执行命令时,无论先前的core模块是否存在于本地Repository中,父工程都能够获取到core模块(如果不存在于本地Repository,它将现场编译core模块,再将其做为webapp的依赖,比如此时使用“mvn clean package”也是能够构建成功的),所以一切成功。


三、关于继承的概念

(1),继承的概念

如果在 core 和 webapp 工程的 pom.xml 文件中,有下面的代码的话,代表 maven-multi-module 工程是各自的父工程,可以从 maven-multi-module 工程继承一依赖和插件等。

<parent>
  <artifactId>maven-multi-module</artifactId>
  <groupId>my.group</groupId>
  <version>1.0-SNAPSHOT</version>
</parent>

(2),继承的好处

当子模块中,有很多相同的依赖插件的话,可以定义在父工程中,只需要在模块中引用一下即可(其实只是省略了版本号)。依赖和插件的共享,使用了<dependencyManagement><pluginManagement>标签。

关于依赖

例如:父工程 pom.xml 内容如下:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactid>junit</artifactId>
      <version>4.8.2</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactid>log4j</artifactId>
      <version>1.2.16</version>
    </dependency>
  </dependencies>
</dependencyManagement>

子模块如果想使用 junit 和 Log4j 的话,只需要像下面这样声明:(省略了版本号)

  <dependency>
    <groupId>junit</groupId>
    <artifactid>junit</artifactId>
  </dependency>
  <dependency>
    <groupId>log4j</groupId>
    <artifactid>log4j</artifactId>
  </dependency>

关于插件

与dependencyManagement类似的,我们也可以使用pluginManagement元素管理插件。一个常见的用法就是我们希望项目所有模块的使用Maven Compiler Plugin的时候,都使用Java 1.5,以及指定Java源文件编码为UTF-8,这时可以在父模块的POM中如下配置pluginManagement:

<build>
  <pluginManagement>
    <plugins>
      <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>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>
    </plugins>
  </pluginManagement>
</build>

四、模块 VS 继承

在Maven中,由多模块(Project Aggregation)和继承(Project Inheritance)关系并不必同时存在。

(1)如果保留webapp和core中对maven-multi-module的父关系声明,即保留 <parent>... </parent>,而删除maven-multi-module中的子模块声明,即<modules>...<modules>,会发生什么情况?此时,整个工程已经不是一个多模块工程,而只是具有父子关系的多个工程集合。如果我们在maven-multi-module目录下执行“mvn clean install”,Maven只会在maven-multi-module本身上执行该命令,继而只会将maven-multi-module安装到本地Repository中,而不会在webapp和core模块上执行该命令,因为Maven根本就不知道这两个子模块的存在。另外,如果我们在webapp目录下执行相同的命令,由于由子到父的关系还存在,Maven会在本地的Repository中找到maven-multi-module的pom.xml文件和对core的依赖(当然前提是他们存在于本地的Repository中),然后顺利执行该命令。

这时,如果我们要发布webapp,那么我们需要先在maven-multi-module目录下执行“mvn clean install”将最新的父pom安装在本地Repository中,再在core目录下执行相同的命令将最新的core模块安装在本地Repository中,最后在webapp目录下执行相同的命令完成最终war包的安装。麻烦。

(2)如果保留maven-multi-module中的子模块声明,而删除webapp和core中对maven-multi-module的父关系声明,又会出现什么情况呢?此时整个工程只是一个多模块工程,而没有父子关系。Maven会正确处理模块之间的依赖关系,即在webapp模块上执行Maven命令之前,会先在core模块上执行该命令,但是由于core和webapp模块不再继承自maven-multi-module,对于每一个依赖,他们都需要自己声明,比如我们需要分别在webapp和core的pom.xml文件中声明对Junit依赖。

综上,多模块和父子关系是不同的。如果core和webapp只是在逻辑上属于同一个总工程,那么我们完全可以只声明模块关系,而不用声明父子关系。如果core和webapp分别处理两个不同的领域,但是它们又共享了很多,比如依赖等,那么我们可以将core和webapp分别继承自同一个父pom工程,而不必属于同一个工程下的子模块。


五、更细致的划分依赖(Import)

我们知道Maven的继承和Java的继承一样,是无法实现多重继承的,如果10个、20个甚至更多模块继承自同一个模块,那么按照我们之前的做法,这个父模块的dependencyManagement会包含大量的依赖。如果你想把这些依赖分类以更清晰的管理,那就不可能了,import scope依赖能解决这个问题。你可以把dependencyManagement放到单独的专门用来管理依赖的POM中,然后在需要使用依赖的模块中通过import scope依赖,就可以引入dependencyManagement。例如可以写这样一个用于依赖管理的POM:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.juvenxu.sample</groupId>
  <artifactId>sample-dependency-infrastructure</artifactId>
  <packaging>pom</packaging>
  <version>1.0-SNAPSHOT</version>
  <dependencyManagement>
    <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactid>junit</artifactId>
          <version>4.8.2</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>log4j</groupId>
          <artifactid>log4j</artifactId>
          <version>1.2.16</version>
        </dependency>
    </dependencies>
  </dependencyManagement>
</project>

然后就可以通过非继承的方式来引入这段依赖管理配置:

<dependencyManagement>
  <dependencies>
      <dependency>
        <groupId>com.juvenxu.sample</groupId>
        <artifactid>sample-dependency-infrastructure</artifactId>
        <version>1.0-SNAPSHOT</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
  </dependencies>
</dependencyManagement>

<dependency>
  <groupId>junit</groupId>
  <artifactid>junit</artifactId>
</dependency>
<dependency>
  <groupId>log4j</groupId>
  <artifactid>log4j</artifactId>
</dependency>

参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值