Ce site met a disposition le build journalier de la traduction francaise du Maven: The Definitive Guide
Consultez :
  • Les documents de reference sur le projet original
  • Les sources de la traduction fr sur GitHub
  • maven


    8.6.2. Assembly de distribution (agrégation)

    Comme mentionné ci-dessus, le plugin Assembly fournit plusieurs façons de créer de nombreux formats d'archives. Les assemblies de distribution sont généralement de très bons exemples, car ils combinent souvent des modules à partir d'un build multimodule, avec leurs dépendances et, éventuellement, d'autres fichiers en plus de ces artefacts. La distribution vise à inclure ces différentes sources en une seule archive que l'utilisateur pourra télécharger, décompresser et exécuter. Toutefois, nous avons également vu un certain nombre d'inconvénients potentiels pouvant être provoqués par l'utilisation de la balise moduleSets du descripteur d'assembly - les relations parent-enfant entre les POMs d'un build peuvent, dans certains cas, rendre indisponible les artefacts des modules.

    Plus précisément, si les POMs des modules référencent comme parent le POM qui contient la configuration du plugin-assembly, le projet parent devra être construit avant les projets modules lors de l'exécution du build. Or, l'assembly du parent s'attend à trouver les artefacts de ses modules, mais ces projets attendent également la fin de la construction de leur parent. On arrive donc à une situation de bloquage empêchant la construction du parent. En d'autres termes, le projet enfant dépend du projet parent qui dépend à son tour du projet enfant.

    À titre d'exemple, considérons le descripteur d'assembly ci-dessous. Il est conçu pour être utilisé à partir du projet de plus haut niveau de la hiérarchie multimodule :

    <assembly>
      <id>distribution</id>
      <formats>
        <format>zip</format>
        <format>tar.gz</format>
        <format>tar.bz2</format>
      </formats>
      
      <moduleSets>
        <moduleSet>
          <includes>
            <include>*-web</include>
          </includes>
          <binaries>
            <outputDirectory>/</outputDirectory>
            <unpack>true</unpack>
            <includeDependencies>true</includeDependencies>
            <dependencySets>
              <dependencySet>
                <outputDirectory>/WEB-INF/lib</outputDirectory>
              </dependencySet>
            </dependencySets>
          </binaries>
        </moduleSet>
        <moduleSet>
          <includes>
            <include>*-addons</include>
          </includes>
          <binaries>
            <outputDirectory>/WEB-INF/lib</outputDirectory>
            <includeDependencies>true</includeDependencies>
            <dependencySets>
              <dependencySet/>
            </dependencySets>
          </binaries>
        </moduleSet>
      </moduleSets>
    </assembly>

    Pour un projet parent donné - appelé app-parent - contenant trois modules : app-core, app-web et app-addons, notez ce qu'il se passe lorsque nous essayons d'exécuter ce build multimodule :

    $ mvn package
    [INFO] Reactor build order: 
    [INFO]   app-parent <----- PARENT BUILDS FIRST
    [INFO]   app-core
    [INFO]   app-web
    [INFO]   app-addons
    [INFO] ---------------------------------------------------------------
    [INFO] Building app-parent
    [INFO]    task-segment: [package]
    [INFO] ---------------------------------------------------------------
    [INFO] [site:attach-descriptor]
    [INFO] [assembly:single {execution: distro}]
    [INFO] Reading assembly descriptor: src/main/assembly/distro.xml
    [INFO] ---------------------------------------------------------------
    [ERROR] BUILD ERROR
    [INFO] ---------------------------------------------------------------
    [INFO] Failed to create assembly: Artifact:
    org.sonatype.mavenbook.assemblies:app-web:jar:1.0-SNAPSHOT (included by module) 
    does not have an artifact with a file. Please ensure the package phase is 
    run before the assembly is generated.
    ...

    Le projet parent - app-parent - est le premier à être construit. C'est parce que chacun des autres projets désigne ce POM comme son parent, forçant ainsi l'ordre de construction. Le module app-web, qui est le premier module désigné dans le descripteur d'assembly, n'a pas encore été construit. Par conséquent, il ne dispose d'aucun des artefacts qui lui sont associés, et donc la construction de l'assembly est impossible.

    Une solution de contournement consiste à supprimer la balise executions de la déclaration du plugin Assembly. Celle-ci lie le plugin à la phase package du cycle de vie dans le fichier POM parent. Une fois cette suppression effectuée, exécutez ces deux tâches Maven : la première, package, permet de construire le projet multimodule ; et la seconde, assembly:assembly, pour invoquer directement le plugin assembly qui va utiliser les artefacts construits lors de l'exécution précédente pour construire le paquet de distribution. Pour effectuer cela, utilisez la ligne de commande suivante :

    $ mvn package assembly:assembly

    Cependant, cette approche présente plusieurs inconvénients. Premièrement, elle rend le processus d'assemblage plus complexe en lui rajoutant une tâche manuelle qui peut accroître les risques d'erreur. En outre, cela pourrait signifier que les artefacts joints - qui sont associés en mémoire lors de l'exécution de la construction du projet - ne seront pas accessibles au second passage sans recourir à des références au système de fichiers.

    Au lieu d'utiliser la balise moduleSet pour lister les artefacts du projet multimodule, il est souvent préférable d'utiliser une approche moins technique : à l'aide d'un module dédié à la distribution et aux dépendances inter-projet. Avec cette approche, vous créez un nouveau module dans votre build dont le seul but est d'effectuer l'assemblage. Le POM de ce module contient des références aux dépendances des autres modules, et il configure le plugin Assembly pour qu'il soit rattaché à la phase package de son cycle de vie. Le descripteur d'assembly lui-même utilise une section dependencySets à la place d'un moduleSets pour lister les artefacts et déterminer où les inclure dans l'archive résultante. Cette approche évite les inconvénients liés à la relation parent-enfant mentionnés plus haut, et offre l'avantage d'utiliser une section de configuration plus simple dans le descripteur d'assembly.

    Pour cela, nous pouvons créer une nouvelle structure de projet qui ressemble fortement à celle utilisée par l'approche module-set présentée précédemment. Avec l'ajout de ce nouveau projet de distribution, vous devriez avoir cinq POMs au total : app-parent, app-core, app-web, app-addons et app-distribution. Le nouveau POM app-distribution devrait ressembler à cela :

    <project>
      <parent>
        <artifactId>app-parent</artifactId>
        <groupId>org.sonatype.mavenbook.assemblies</groupId>
        <version>1.0-SNAPSHOT</version>
      </parent>
      <modelVersion>4.0.0</modelVersion>
      <artifactId>app-distribution</artifactId>
      <name>app-distribution</name>
      
      <dependencies>
        <dependency>
          <artifactId>app-web</artifactId>
          <groupId>org.sonatype.mavenbook.assemblies</groupId>
          <version>1.0-SNAPSHOT</version>
          <type>war</type>
        </dependency>
        <dependency>
          <artifactId>app-addons</artifactId>
          <groupId>org.sonatype.mavenbook.assemblies</groupId>
          <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- Not necessary since it's brought in via app-web.
        <dependency> [2]
          <artifactId>app-core</artifactId>
          <groupId>org.sonatype.mavenbook.assemblies</groupId>
          <version>1.0-SNAPSHOT</version>
        </dependency>
        -->
      </dependencies>
    </project>
    

    Notez que nous devons inclure les dépendances vers les autres modules dans la structure du projet puisque nous n'avons pas de section modules dans ce POM. Notez aussi que nous n'utilisons pas de dépendance explicite vers app-core. Puisqu'il s'agit également d'une dépendance du projet app-web, nous n'avons pas besoin de la traiter (ou, d'éviter de la traiter) à deux reprises.

    Ensuite, lorsque nous déplaçons le descripteur d'assembly distro.xml dans le projet app-distribution, nous devons également modifier la configuration de la section dependencySets :

    <assembly>
      ...
      <dependencySets>
        <dependencySet>
          <includes>
            <include>*-web</include>
          </includes>
          <useTransitiveDependencies>false</useTransitiveDependencies>
          <outputDirectory>/</outputDirectory>
          <unpack>true</unpack>
        </dependencySet>
        <dependencySet>
          <excludes>
            <exclude>*-web</exclude>
          </excludes>
          <useProjectArtifact>false</useProjectArtifact>
          <outputDirectory>/WEB-INF/lib</outputDirectory>
        </dependencySet>
      </dependencySets>
      ...
    </assembly>
    

    Cette fois, si nous lançons la construction à partir du répertoire de plus haut niveau du projet, nous obtiendrons de meilleurs résultats :

    $ mvn package
    (...)
    [INFO] ---------------------------------------------------------------
    [INFO] Reactor Summary:
    [INFO] ---------------------------------------------------------------
    [INFO] module-set-distro-parent ...............SUCCESS [3.070s]
    [INFO] app-core .............................. SUCCESS [2.970s]
    [INFO] app-web ............................... SUCCESS [1.424s]
    [INFO] app-addons ............................ SUCCESS [0.543s]
    [INFO] app-distribution ...................... SUCCESS [2.603s]
    [INFO] ---------------------------------------------------------------
    [INFO] ---------------------------------------------------------------
    [INFO] BUILD SUCCESSFUL
    [INFO] ---------------------------------------------------------------
    [INFO] Total time: 10 seconds
    [INFO] Finished at: Thu May 01 18:00:09 EDT 2008
    [INFO] Final Memory: 16M/29M
    [INFO] ---------------------------------------------------------------

    Comme vous pouvez le voir, l'approche par dependency-set est beaucoup plus stable et - aussi longtemps que la logique interne de tri de Maven ne sera pas aussi perfcetionnée que celle du plugin Assembly - offre moins de possibilités de se tromper lors de l'exécution d'un build.