高级模块集主题

快速笔记

本文档中的一些主题是指更通用的主题或对整个程序集描述符的改进。有关详细信息,请参阅高级程序集描述符主题页面。

使用 ModuleSet 包含和排除模块

毫无疑问,Maven 引入了多模块构建的高级处理。这些构建包含多个通常相互关联的项目。在这些构建中,项目层次结构是通过使用 POM 的模块部分建立的,其中父 POM 在模块部分中指定其子项。其他关系,如相互依赖关系,也存在于多模块构建中;但是,这些超出了本文档的范围。

在多模块构建中从任何父级项目构建程序集时,可以处理此父 POM 的后代模块,并以某种形式将它们包含在生成的程序集工件中。默认情况下,当前项目下方的整个模块层次结构可用于包含或排除。此外,模块的包含/排除模式使用Advanced Assembly-Descriptor Topics文档中解释的工件匹配规则进行匹配。

以下示例描述了如何使用基本工件包含/排除来选择项目层次结构中的某些模块。它没有描述如何处理选定的模块;要了解可用于选定模块的操作,请参阅下面的包含模块源包含模块二进制文件。有关其他更高级的模块处理选项,请继续阅读!

示例:从一组子项目中选择一个

给定以下项目结构,以及父 POM 中所有适当的模块引用:

+ parent (groupId: org.test, artifactId: parent)
  |
  + child1 (groupId: org.test, artifactId: child1)
  |
  + child2 (groupId: org.test, artifactId: child2)

我们可以使用以下moduleSet选择 child1 模块:

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
  [...]
  <moduleSets>
    [...]
    <moduleSet>
      <includes>
        <include>org.test:child1</include>
      </includes>
    </moduleSet>
  </moduleSets>
  [...]
</assembly>

注意:重要的是要记住,如果 child1 项目本身有孩子,这些孩子不会因为包含 child1 项目而被包括在内。每个模块单独匹配。

ModuleSets中outputFileNameMapping的快速说明

moduleSet中使用时,所有带有${artifactId}等表达式的outputFileNameMapping配置都会从相关工件中提取信息。

示例:从moduleSet/binaries设置outputFileNameMapping

给定一个具有以下内容的模块:

Group Id: org.test
Artifact Id: project
Version: 1.0.1
Type: jar

以下输出文件名映射

${module.groupId}-${module.artifactId}-${module.version}.${module.extension}

将导致在程序集中创建一个名为org.test-project-1.0.jar的文件。

注意:表达式 ${module.extension} 映射到 ArtifactHandler 为类型 jar提供的文件扩展名。重要的是要记住文件扩展名 不必是 .jar

包括模块源

选择要包含在程序集中的某些模块后,您必须确定要从每个模块中包含的内容。这通常取决于装配的目的。例如,如果您正在构建一个二进制程序集,以便在运行时上下文中使用,您可能只想包含模块二进制文件(请参阅下面的Include_Module_Binaries部分)。但是,如果您的程序集旨在包含项目源,作为参考或允许用户构建您的项目(或完全出于其他原因),那么您可能对moduleSet的部分感兴趣。

处理模块源是一个基于文件集的活动。也就是说,根据文件匹配模式或显式文件集子节来包含或排除源。仅出于向后兼容性<sources/>部分本身支持包含排除,这可以帮助确定应处理模块目录中的哪些文件。从 2.2 版的程序集插件开始,<sources/>部分支持<fileSets/>子部分,这是选择模块源文件进行处理的首选方式。

示例:包括每个选定模块的src目录

在这个例子中,我们将探索如何为 moduleSet 选择的每个模块包含src目录。这对于向用户提供项目的源代码参考很有用。

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
  [...]
  <moduleSets>
    [...]
    <moduleSet>
      [...]
      <sources>
        <fileSets>
          <fileSet>
            <directory>src</directory>
          </fileSet>
        </fileSets>
      </sources>
    </moduleSet>
  </moduleSets>
</assembly>

示例:为每个选定的模块包含一个可构建的项目目录

在此示例中,我们将探索如何在您的程序集中为每个选定的模块包含一个完整的可构建项目目录。这对于让您的用户有机会修改您的项目,然后自己构建它很有用。

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
  [...]
  <moduleSets>
    [...]
    <moduleSet>
      [...]
      <sources>
        <fileSets>
          <fileSet>
            <excludes>
              <exclude>target/**</exclude>
            </excludes>
          </fileSet>
        </fileSets>
      </sources>
    </moduleSet>
  </moduleSets>
</assembly>

注意:我们排除了目标目录,因为它被假定为在 Maven 构建过程中生成的文件的临时存储。永久项目文件不应该驻留在此处...

将所有模块源合并到一个目录结构中

通常,程序集插件处理的每个模块都放置在程序集根目录内自己的目录结构中。对于模块源,此模块特定目录的默认名称是模块的artifactId

但是,在某些情况下,您可能希望将模块源合并到相同的目录结构中,基于程序集根目录。为此,只需将includeModuleDirectory标志设置为false

示例:将所有模块源复制到单个src目录中

在向用户提供源引用时,您可能希望生成一个单一的、合并的源目录,其中包含多模块层次结构中的所有源文件。

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
  [...]
  <moduleSets>
    [...]
    <moduleSet>
      [...]
      <sources>
        <includeModuleDirectory>false</includeModuleDirectory>
        <fileSets>
          <fileSet>
            <outputDirectory>src</outputDirectory>
            <includes>
              <include>src/**</include>
            </includes>
          </fileSet>
        </fileSets>
      </sources>
    </moduleSet>
  </moduleSets>
</assembly>

从直接组装处理中排除模块的模块

在处理由多层模块分组组成的复杂多模块构建中的项目源时,有时需要只处理顶层模块,并提供文件集规范来处理子模块。这可以更容易地保留项目目录结构,因为它不会强制所有模块 - 无论它们在项目层次结构中的位置如何 - 通过平面模块处理机制。仅处理第一级模块是moduleSet的部分的默认配置。

要显式处理模块的模块 - 子模块,即 - 只需使用excludeSubModuleDirectories标志,设置为false

示例:提供浅层源目录结构以供参考

考虑您希望根据项目所属的项目保留项目层次结构中所有源文件的上下文的情况。同时,您希望避免让用户对项目中的复杂项目嵌套感到困惑,并提供一个简单的项目列表以供浏览。

如果您的项目层次结构如下所示:

+ application
  |
  + src
  |
  + project1
  | |
  | + src
  | |
  | + project1-child1
  | | |
  | | + src
  | |
  | + project1-child2
  | | |
  | | + src
  |
  + project2
    |
    + src
    |
    + project2-child1
      |
      + src

您可能希望它在生成的程序集中看起来像这样:

+ application
| |
| + src
|
+ project1
| |
| + src
|
+ project1-child1
| |
| + src
|
+ project1-child2
| |
| + src
|
+ project2
| |
| + src
|
+ project2-child1
  |
  + src

要完成此重组,只需使用excludeSubModuleDirectories标志,如下所示:

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
  [...]
  <moduleSets>
    [...]
    <moduleSet>
      [...]
      <sources>
        <excludeSubModuleDirectories>false</excludeSubModuleDirectories>
        <fileSets>
          <fileSet>
            <includes>
              <include>src/**</include>
            </includes>
          </fileSet>
        </fileSets>
      </sources>
    </moduleSet>
  </moduleSets>
</assembly>

包括模块二进制文件

警告!使用moduleSet定义的二进制部分涉及一些棘手的考虑,这是 Maven 在多模块上下文中排序和执行项目构建的方式的结果。如果您决定使用它们,请阅读此常见问题解答条目。

如果您的程序集工件打算在运行时上下文中使用,您很可能希望包含来自程序集插件处理的任何模块的二进制文件。这可以像将模块的 jar 工件添加到您的程序集存档一样简单;或者,除了模块自己的 jar 之外,它还可以选择性地包括该模块的依赖项。

无论如何,处理模块二进制文件是基于工件的活动。因此,为给定模块选择适当的工件遵循高级装配描述符主题文档中解释的工件包含规则。

一旦您选择了应该为特定模块处理哪些工件,您就可以选择如何处理它们。在最简单的形式中,moduleSet的二进制部分具有许多与dependencySet相同的特征。也就是说,您可以选择指定outputDirectory,并且您可以选择是否解压缩工件 - 默认操作将解压缩它们。

处理模块的附件工件

有时,重要的是可以选择从不是主要项目工件的模块中添加工件。此类工件可能包括 javadocs、项目源,甚至其他组装工件。

示例:在当前程序集中包含其他程序集

假设我们有以下项目结构:

+ application
  |
  + app-db
  |
  + app-web
  |
  + app-site

此外,假设程序集插件当前正在应用程序级别执行,但之前已为应用程序站点项目创建了另一个程序集存档。这个其他程序集存档是一个包含项目网站的 zip 文件。我们希望在我们正在创建的应用程序分发程序集中包含该网站的副本。

最后,假设网站附件有一个取自 assemblyId的站点分类器。

由于包含app-site生成的网站的 zip 文件是该模块中的附加工件,因此我们需要提取该工件而不是主项目工件。

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
  [...]
  <moduleSets>
    <moduleSet>
      <includes>
        <include>*:app-site</include>
      </includes>
      <binaries>
        <attachmentClassifier>site</attachmentClassifier>
        <outputDirectory>doc</outputDirectory>
        <outputFileNameMapping>website.${module.extension}</outputFileNameMapping>
      </binaries>
    </moduleSet>
    [...]
  </moduleSets>
</assembly>

排除模块依赖项

就像任何二进制文件一样,模块通常具有运行时依赖项,没有它们它们将无法执行。默认情况下,包含模块本身时会包含模块依赖项。但是,正如我们在上面的示例中看到的,有时这可能不合适。

在上面的示例中,包含的模块二进制文件是包含应用程序网站的程序集工件。其他程序集可能包含模块二进制文件的完全独立版本,所有依赖类都解包并内联在存档中。

简而言之,有时我们想关闭自动依赖包含。我们可以通过将includeDependencies标志设置为false来实现这一点。

示例:包含一个jar-with-dependencies模块程序集

假设我们有以下项目结构:

+ application
  |
  + app-db
  |
  + app-web

此外,假设程序集插件当前正在app-web级别执行,但之前已使用内置jar-with-dependencies程序集描述符为app-db项目创建了另一个程序集存档。此程序集存档包含所有模块依赖项,因此不必在当前程序集中包含此模块的依赖项。

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
  [...]
  <moduleSets>
    <moduleSet>
      <includes>
        <include>*:app-db</include>
      </includes>
      <binaries>
        <attachmentClassifier>jar-with-dependencies</attachmentClassifier>
        <outputDirectory>lib</outputDirectory>
        <outputFileNameMapping>${module.artifactId}-${module.version}-${module.classifier}.${module.extension}</outputFileNameMapping>
      </binaries>
    </moduleSet>
    [...]
  </moduleSets>
</assembly>

注意: 二进制 部分仍然包含直接的 <includes/> <excludes/> 子部分,用于指定要包含在程序集中的模块依赖项。但是,这些已被弃用,仅提供向后兼容性。