Maven parent pom vs módulos pom

284

Parece que hay varias formas de estructurar los padres poms en una compilación multiproyecto y me pregunto si alguien tuvo alguna idea sobre cuáles son las ventajas / inconvenientes en cada sentido.

El método más simple de tener un pom padre sería ponerlo en la raíz de un proyecto, es decir

myproject/
  myproject-core/
  myproject-api/
  myproject-app/
  pom.xml

donde pom.xml es tanto el proyecto principal como describe los módulos -core -api y -app

El siguiente método es separar al padre en su propio subdirectorio como en

myproject/
  mypoject-parent/
    pom.xml
  myproject-core/
  myproject-api/
  myproject-app/

Donde el pom padre todavía contiene los módulos pero son relativos, por ejemplo ../myproject-core

Finalmente, existe la opción donde la definición del módulo y el padre se separan como en

myproject/
  mypoject-parent/
    pom.xml
  myproject-core/
  myproject-api/
  myproject-app/
  pom.xml

Donde el pom padre contiene cualquier configuración "compartida" (dependencyManagement, propiedades, etc.) y myproject / pom.xml contiene la lista de módulos.

La intención es ser escalable a una construcción a gran escala, por lo que debería ser escalable a una gran cantidad de proyectos y artefactos.

Algunas preguntas extra:

  • ¿Dónde es el mejor lugar para definir las diversas configuraciones compartidas como en el control de origen, directorios de implementación, complementos comunes, etc. (Asumo que es el padre pero a menudo me ha mordido esto y terminaron en cada proyecto en lugar de uno común).
  • ¿Cómo lidian el complemento de lanzamiento de Maven, Hudson y Nexus con la forma en que configuran sus proyectos múltiples (posiblemente una pregunta gigante, es más si alguien ha quedado atrapado cuando se ha configurado una construcción de proyectos múltiples)?

Editar: cada uno de los subproyectos tiene su propio pom.xml, lo dejé fuera para mantenerlo conciso.

Jamie McCrindle
fuente
¿Los módulos tienen cada uno su propio pom también? Mi proyecto tiene un pom padre, pero los módulos también tienen un pom. (quizás una cuarta forma de lo que describe)
harschware
Ah, sí, editaré y actualizaré. Cada uno de los submódulos también tiene su propio pom.
Jamie McCrindle
3
Solo como una actualización, puedo ver que una ventaja de la segunda opción es que es más fácil de administrar en Eclipse, donde la raíz pom.xml en el primer y tercer ejemplo sería difícil de incluir si los submódulos son proyectos separados en Eclipse.
Jamie McCrindle

Respuestas:

166

En mi opinión, para responder a esta pregunta, debe pensar en términos del ciclo de vida del proyecto y el control de versiones. En otras palabras, ¿el pom padre tiene su propio ciclo de vida, es decir, se puede liberar por separado de los otros módulos o no?

Si la respuesta es (y este es el caso de la mayoría de los proyectos que se han mencionado en la pregunta o en los comentarios), entonces el padre pom necesita su propio módulo desde un VCS y desde un punto de vista de Maven y terminará con algo como esto en el nivel VCS:

root
|-- parent-pom
|   |-- branches
|   |-- tags
|   `-- trunk
|       `-- pom.xml
`-- projectA
    |-- branches
    |-- tags
    `-- trunk
        |-- module1
        |   `-- pom.xml
        |-- moduleN
        |   `-- pom.xml
        `-- pom.xml

Esto hace que el proceso de pago sea un poco doloroso y una forma común de lidiar con eso es usarlo svn:externals. Por ejemplo, agregue un trunksdirectorio:

root
|-- parent-pom
|   |-- branches
|   |-- tags
|   `-- trunk
|       `-- pom.xml
|-- projectA
|   |-- branches
|   |-- tags
|   `-- trunk
|       |-- module1
|       |   `-- pom.xml
|       |-- moduleN
|       |   `-- pom.xml
|       `-- pom.xml
`-- trunks

Con la siguiente definición externa:

parent-pom http://host/svn/parent-pom/trunk
projectA http://host/svn/projectA/trunk

Una comprobación de trunksentonces daría como resultado la siguiente estructura local (patrón # 2):

root/
  parent-pom/
    pom.xml
  projectA/

Opcionalmente, incluso puede agregar un pom.xmlen el trunksdirectorio:

root
|-- parent-pom
|   |-- branches
|   |-- tags
|   `-- trunk
|       `-- pom.xml
|-- projectA
|   |-- branches
|   |-- tags
|   `-- trunk
|       |-- module1
|       |   `-- pom.xml
|       |-- moduleN
|       |   `-- pom.xml
|       `-- pom.xml
`-- trunks
    `-- pom.xml

Este pom.xmles un tipo de pom "falso": nunca se lanza, no contiene una versión real ya que este archivo nunca se lanza, solo contiene una lista de módulos. Con este archivo, un pago resultará en esta estructura (patrón # 3):

root/
  parent-pom/
    pom.xml
  projectA/
  pom.xml

Este "truco" permite lanzar una construcción de reactor desde la raíz después de un pago y hacer las cosas aún más útiles. En realidad, así es como me gusta configurar proyectos maven y un repositorio VCS para grandes construcciones : simplemente funciona, se escala bien, brinda toda la flexibilidad que pueda necesitar.

Si la respuesta es no (volviendo a la pregunta inicial), entonces creo que puedes vivir con el patrón # 1 (haz lo más simple que pueda funcionar).

Ahora, sobre las preguntas de bonificación:

  • ¿Dónde es el mejor lugar para definir las diversas configuraciones compartidas como en el control de origen, directorios de implementación, complementos comunes, etc. (Asumo que es el padre pero a menudo me ha mordido esto y terminaron en cada proyecto en lugar de uno común).

Honestamente, no sé cómo no dar una respuesta general aquí (como "usa el nivel en el que crees que tiene sentido mutualizar las cosas"). Y de todos modos, los poms secundarios siempre pueden anular la configuración heredada.

  • ¿Cómo lidian el complemento de lanzamiento de Maven, Hudson y Nexus con la forma en que configuran sus proyectos múltiples (posiblemente una pregunta gigante, es más si alguien ha quedado atrapado cuando se ha configurado una construcción de proyectos múltiples)?

La configuración que uso funciona bien, nada en particular que mencionar.

En realidad, me pregunto cómo el plugin maven-release-plugin trata con el patrón # 1 (especialmente con la <parent>sección ya que no puede tener dependencias SNAPSHOT en el momento del lanzamiento). Esto suena como un problema de huevo o gallina, pero no puedo recordar si funciona y fue demasiado vago para probarlo.

Pascal Thivent
fuente
Eso es muy bueno, ya que puedo ver cómo se escala. El svn: externos responde a mi preocupación acerca de que sea engorroso.
Jamie McCrindle
@jamie Me alegra que lo encuentres útil.
Pascal Thivent
1
¿Podría dar más detalles sobre cómo hacer que el "hack" funcione? Tengo el proyecto Trunks y anticipo que apuntas a la opción -pl con "lanzamiento de una construcción de reactor", pero esto se presenta como un problema al hacer un lanzamiento en la estructura porque esta opción no pasa de una construcción a nivel raíz ni ¿Puedo colocarlo en la opción <argumentos /> del Release-Plugin? Por lo tanto la liberación: realizar failes porque trata de trabajo en el nivel de la raíz del pom-...
Ene
El hack svn: externals es el hack svn más útil que he visto en mucho tiempo. Muy útil con proyectos que tienen ramificaciones por proyecto dentro del mismo repositorio.
omerkudat
1
Hola Pascal, ¿cómo manejarías la versión # si los proyectos que se mencionan en la sección de módulos no usan parent-pom como su <parent> sino algún otro proyecto-parent-pom? ¿Qué versiones # obtendremos para un artefacto de tales proyectos (versión # del artefacto en la sección <parent> de esos proyectos O versión # del Proyecto que enumera estos proyectos como módulos)? stackoverflow.com/questions/25918593/…
AKS
34

Según mi experiencia y las mejores prácticas de Maven, hay dos tipos de "padres poms"

  • pom padre de "empresa": este pom contiene la información y la configuración específicas de su empresa que heredan cada pom y no necesitan copiarse. Estas informaciones son:

    • repositorios
    • secciones de gestión de distribución
    • configuraciones comunes de complementos (como las versiones de origen y destino de maven-compiler-plugin)
    • organización, desarrolladores, etc.

    La preparación de este pom padre debe hacerse con precaución, ya que todos los poms de su empresa heredarán de ella, por lo que este pom debe ser maduro y estable (¡liberar una versión de pom padre no debería afectar para liberar todos los proyectos de su empresa!)

  • El segundo tipo de padre pom es un padre multimódulo. Prefiero su primera solución: esta es una convención predeterminada de Maven para proyectos de módulos múltiples, a menudo representa la estructura del código VCS

La intención es ser escalable a una construcción a gran escala, por lo que debería ser escalable a una gran cantidad de proyectos y artefactos.

Los multiproyectos tienen una estructura de árboles, por lo que no estás reducido a un solo nivel de padre pom. Intente encontrar una estructura de proyecto adecuada para sus necesidades: un ejemplo clásico es cómo distribuir proyectos de módulos múltiples

distibution/
documentation/
myproject/
  myproject-core/
  myproject-api/
  myproject-app/
  pom.xml
pom.xml

Algunas preguntas extra:

  • ¿Dónde es el mejor lugar para definir las diversas configuraciones compartidas como en el control de origen, directorios de implementación, complementos comunes, etc. (Asumo que es el padre pero a menudo me ha mordido esto y terminaron en cada proyecto en lugar de uno común).

Esta configuración debe dividirse sabiamente en un pom padre de "empresa" y pom padres del proyecto. Las cosas relacionadas con todo lo que proyecta van al padre de la "compañía" y esto está relacionado con el proyecto actual.

  • ¿Cómo lidian el complemento de lanzamiento de Maven, Hudson y Nexus con la forma en que configuran sus proyectos múltiples (posiblemente una pregunta gigante, es más si alguien ha quedado atrapado cuando se ha configurado una construcción de proyectos múltiples)?

La empresa matriz pom debe ser lanzada primero. Para multiproyectos se aplican reglas estándar. El servidor de CI necesita saber todo para construir el proyecto correctamente.

cetnar
fuente
1
Para que haya dos tipos de proyectos principales / poms. Uno sin declaración de <modules>. Este es el que se utiliza para la herencia. Y un proyecto padre con declaración <multimodule>. Este es el que los submódulos no heredan, es solo para administrar la construcción del proyecto de retención. Estoy en lo cierto?
lisak
22
  1. Un padre independiente es la mejor práctica para compartir configuraciones y opciones a través de componentes que de otro modo no estarían acoplados. Apache tiene un proyecto pom padre para compartir avisos legales y algunas opciones comunes de empaque.

  2. Si su proyecto de nivel superior tiene un trabajo real en él, como agregar javadoc o empaquetar un lanzamiento, entonces tendrá conflictos entre la configuración necesaria para hacer ese trabajo y la configuración que desea compartir a través de los padres. Un proyecto solo para padres evita eso.

  3. Un patrón común (ignorando el n. ° 1 por el momento) es hacer que los proyectos con código usen un proyecto padre como padre y que usen el nivel superior como padre. Esto permite que todos compartan las cosas principales, pero evita el problema descrito en el n. ° 2.

  4. El complemento del sitio se confundirá mucho si la estructura principal no es la misma que la estructura del directorio. Si desea construir un sitio agregado, necesitará hacer algunos ajustes para evitar esto.

  5. Apache CXF es un ejemplo del patrón en el n. ° 2.

bmargulies
fuente
2
He echado un vistazo a ibilio y muchos proyectos parecen preferir el pom padre "independiente". Hibernate, ActiveMQ, Jetty, XStream, etc. Lo que sugiere que es el mecanismo de facto.
Jamie McCrindle
2
Otra desventaja del padre independiente parece ser que el complemento de lanzamiento de Maven parece querer que el padre sea anclado a una versión antes de que se publique. Probablemente no sea un gran problema ya que los padres no deberían cambiar demasiado.
Jamie McCrindle
9

Hay una pequeña trampa con el tercer enfoque. Dado que los POM agregados (myproject / pom.xml) generalmente no tienen padre en absoluto, no comparten la configuración. Eso significa que todos esos POM agregados solo tendrán repositorios predeterminados.

Eso no es un problema si solo usa complementos de Central, sin embargo, esto fallará si ejecuta el complemento usando el complemento: formato de objetivo desde su repositorio interno. Por ejemplo, puede tener foo-maven-plugincon el groupId de org.exampleproporcionar objetivo generate-foo. Si intenta ejecutarlo desde la raíz del proyecto utilizando un comando como mvn org.example:foo-maven-plugin:generate-foo, no se ejecutará en los módulos agregados (consulte la nota de compatibilidad ).

Son posibles varias soluciones:

  1. Implemente el complemento en Maven Central (no siempre es posible).
  2. Especifique la sección del repositorio en todos sus POM agregados (rompe el principio DRY ).
  3. Tenga este repositorio interno configurado en settings.xml (ya sea en la configuración local en ~ / .m2 / settings.xml o en la configuración global en /conf/settings.xml). Hará que la compilación falle sin esos settings.xml (podría estar bien para grandes proyectos internos que se supone que nunca se construirán fuera de la empresa).
  4. Use la configuración principal con repositorios en sus POM agregados (¿podrían ser demasiados POM principales?).
Ivan Dubrov
fuente