12.2.4. 通过套件依赖组装套件

起这么一个使人困惑的名字是怎么回事?让我们建立这样一个能解释组装套件(assembling assemblies)概念的场景。假设你想要创建一个归档,它包含了一些项目套件。再假设你有一个多模块构建,并且想要部署一个包含很多相关项目套件的套件。在本节的例子中,我们要为一组通常一起被使用的项目创建一个“可构建”的项目目录。为了简便,我们要重用前面讨论的两个projectjar-with-dependencies内置套件描述符。在这个特定的例子中,假设每个项目在主要的JAR构件之外还创建project套件。假设这个多模块构建中每个项目都使用project descriptorRef绑定到package阶段的single目标。每个模块都会从顶层的pom.xml中继承该配置,其pluginManagement元素如Example 12.2, “在顶层POM中配置项目套件”所示:

Example 12.2. 在顶层POM中配置项目套件

<project>
  ...
  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.2-beta-2</version>
          <executions>
            <execution>
              <id>create-project-bundle</id>
              <phase>package</phase>
              <goals>
                <goal>single</goal>
              </goals>
              <configuration>
                <descriptorRefs>
                  <descriptorRef>project</descriptorRef>
                </descriptorRefs>
              </configuration>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
  ...
</project>

每个项目的POM都使用很小的一部分插件声明引用了Example 12.2, “在顶层POM中配置项目套件”中的插件配置,如Example 12.3, “在子项目中激活Assembly插件配置”所示:

Example 12.3. 在子项目中激活Assembly插件配置

<build>
  <plugins>
    <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
    </plugin>
  </plugins>
</build>

要生成一组项目套件,从顶层目录运行mvn install。你会看到Maven使用分类器将套件安装到你的本地仓库。

$ mvn install
...
[INFO] Installing ~/mvn-examples-1.0/assemblies/as-dependencies/project-parent/\
                  second-project/target/second-project-1.0-SNAPSHOT-project.tar.gz to 
       ~/.m2/repository/org/sonatype/mavenbook/assemblies/second-project/1.0-SNAPSHOT/\
                  second-project-1.0-SNAPSHOT-project.tar.gz
...
[INFO] Installing ~/mvn-examples-1.0/assemblies/as-dependencies/project-parent/\
                  second-project/target/second-project-1.0-SNAPSHOT-project.tar.bz2 to 
       ~/.m2/repository/org/sonatype/mavenbook/assemblies/second-project/1.0-SNAPSHOT/\
                  second-project-1.0-SNAPSHOT-project.tar.bz2
...
[INFO] Installing ~/mvn-examples-1.0/assemblies/as-dependencies/project-parent/\
                  second-project/target/second-project-1.0-SNAPSHOT-project.zip to 
       ~/.m2/repository/org/sonatype/mavenbook/assemblies/second-project/1.0-SNAPSHOT/\\
                  second-project-1.0-SNAPSHOT-project.zip
...

当你运行install的时候,Maven会将每个项目的主构件和每个套件复制到你的本地Maven仓库中。现在本地的所有其它项目都可以使用依赖引用这些构件。如果你最终的目的是创建一个包含多个多模块项目构件的软件包,你可以创建一个项目,它以依赖的形式引入其它项目的套件。这个包裹项目(贴切的命名为project-bundle)负责创建一个最终的包裹套件。这个包裹项目的POMExample 12.4, “套件包裹项目的POM”所示:

Example 12.4. 套件包裹项目的POM

<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>
  <groupId>org.sonatype.mavenbook.assemblies</groupId>
  <artifactId>project-bundle</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>
  <name>Assemblies-as-Dependencies Example Project Bundle</name>
  <url>http://sonatype.com/book</url>
  <dependencies>
    <dependency>
      <groupId>org.sonatype.mavenbook.assemblies</groupId>
      <artifactId>first-project</artifactId>
      <version>1.0-SNAPSHOT</version>
      <classifier>project</classifier>
      <type>zip</type>
    </dependency>
    <dependency>
      <groupId>org.sonatype.mavenbook.assemblies</groupId>
      <artifactId>second-project</artifactId>
      <version>1.0-SNAPSHOT</version>
      <classifier>project</classifier>
      <type>zip</type>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.2-beta-2</version>
        <executions>
          <execution>
            <id>bundle-project-sources</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
            <configuration>
              <descriptorRefs>
                <descriptorRef>
                  jar-with-dependencies
                </descriptorRef>
              </descriptorRefs>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

该包裹项目的POM引用了来自于first-projectsecond-project的两个套件。这个POM指定了一个值为project的分类器和一个值为zip的类型,而不是直接引用过了项目的主构件。这告诉Maven去解析project套件创建的ZIP归档。注意包裹项目生成了一个jar-with-dependencies套件。jar-with-dependencies并不创建一个非常简洁的套件,而是简单的创建一个包含所有依赖拆解内容的JAR文件。jar-with-dependencies实际上做的事情是:告诉Maven拿来所有依赖,将其拆解,然后创建一个包含当前项目所有输出的归档。在这个项目中,它的效果就是创建一个带有first-projectsecond-project套件拆解内容的JAR文件,

该样例展示了如何不用自定义套件描述符就能联合Maven Assembly插件的基本能力。它实现了创建一个包含多模块项目内容的单独归档这样一个目的。这个时候,jar-with-dependencies仅仅是一个存储格式,因此我们没必要指定Main-Class的manifest属性。我们只要正常的构建project-bundle项目就能得到套件。

$ mvn package
...
[INFO] [assembly:single {execution: bundle-project-sources}]
[INFO] Processing DependencySet (output=)
[INFO] Building jar: ~/downloads/mvn-examples-1.0/assemblies/as-dependencies/\
        project-bundle/target/project-bundle-1.0-SNAPSHOT-jar-with-dependencies.jar

要验证project-bundle套件是否包含了所有依赖套件的拆解内容,运行jar tf

$ java tf \
  target/project-bundle-1.0-SNAPSHOT-jar-with-dependencies.jar
...
first-project-1.0-SNAPSHOT/pom.xml
first-project-1.0-SNAPSHOT/src/main/java/org/sonatype/mavenbook/App.java
first-project-1.0-SNAPSHOT/src/test/java/org/sonatype/mavenbook/AppTest.java
...
second-project-1.0-SNAPSHOT/pom.xml
second-project-1.0-SNAPSHOT/src/main/java/org/sonatype/mavenbook/App.java
second-project-1.0-SNAPSHOT/src/test/java/org/sonatype/mavenbook/AppTest.java

阅读本节内容之后,标题应该容易理解了。我们使用了一个包裹项目,它依赖于两个项目的套件,然后我们再根据这两个项目的套件装配出一个最终的套件。