Maven padre pom vs moduli pom


284

Sembra che ci siano diversi modi per strutturare i genitori in una build multiprogetto e mi chiedo se qualcuno abbia avuto qualche idea su quali siano i vantaggi / gli svantaggi in ogni modo.

Il metodo più semplice per avere un padre genitore sarebbe metterlo alla radice di un progetto cioè

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

dove pom.xml è sia il progetto principale che descrive i moduli -core -api e -app

Il metodo successivo consiste nel separare il genitore nella propria sottodirectory come in

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

Dove il pom padre contiene ancora i moduli ma sono relativi, ad esempio ../myproject-core

Infine, c'è l'opzione in cui la definizione del modulo e il genitore sono separati come in

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

Dove il pom padre contiene qualsiasi configurazione "condivisa" (dependencyManagement, proprietà ecc.) E il myproject / pom.xml contiene l'elenco dei moduli.

L'intenzione è di essere scalabile su una build su larga scala, quindi dovrebbe essere scalabile su un gran numero di progetti e artefatti.

Alcune domande bonus:

  • Qual è il posto migliore per definire le varie configurazioni condivise come nel controllo del codice sorgente, nelle directory di distribuzione, nei plugin comuni ecc. (Sto assumendo il genitore ma sono stato spesso morso da questo e sono finiti in ogni progetto piuttosto che uno comune).
  • In che modo il plug-in di rilascio Maven, Hudson e Nexus affrontano il modo in cui hai impostato i tuoi multi-progetti (forse una domanda gigantesca, è più se qualcuno è stato sorpreso quando da come è stata creata una build multi-progetto)?

Modifica: Ognuno dei sottoprogetti ha il proprio pom.xml, l'ho lasciato fuori per tenerlo conciso.


Ognuno dei moduli ha anche il proprio pom? Il mio progetto ha un pom genitore, ma ognuno ha anche un pom. (forse un quarto modo per quello che descrivi)
harschware

Ah, sì, lo modificherò e aggiornerò. Ognuno dei sottomoduli ha anche il proprio pom.
Jamie McCrindle,

3
Proprio come un aggiornamento, posso vedere un vantaggio della seconda opzione è che è più facile da gestire in Eclipse, dove la radice pom.xml nel primo e terzo esempio sarebbe difficile da includere se i moduli secondari sono progetti separati in Eclipse.
Jamie McCrindle,

Risposte:


166

A mio avviso, per rispondere a questa domanda, è necessario pensare in termini di ciclo di vita del progetto e controllo della versione. In altre parole, il pom padre ha il suo ciclo di vita, cioè può essere rilasciato separatamente dagli altri moduli o no?

Se la risposta è (e questo è il caso della maggior parte dei progetti che sono stati menzionati nella domanda o nei commenti), allora il genitore pom ha bisogno del suo modulo da un VCS e dal punto di vista di Maven e finirai con qualcosa del genere a livello di VCS:

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

Questo rende il checkout un po 'doloroso e un modo comune per gestirlo è quello di usarlo svn:externals. Ad esempio, aggiungi una trunksdirectory:

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

Con la seguente definizione di esterni:

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

Un checkout trunkscomporterebbe quindi la seguente struttura locale (modello n. 2):

root/
  parent-pom/
    pom.xml
  projectA/

Opzionalmente, puoi anche aggiungere un pom.xmlnella trunksdirectory:

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

Questo pom.xmlè un tipo di pom "falso": non viene mai rilasciato, non contiene una versione reale poiché questo file non viene mai rilasciato, contiene solo un elenco di moduli. Con questo file, un checkout comporterebbe questa struttura (modello n. 3):

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

Questo "hack" consente di avviare una build di reattori dalla radice dopo un checkout e rendere le cose ancora più utili. In realtà, è così che mi piace impostare progetti maven e un repository VCS per build di grandi dimensioni : funziona, scala bene e offre tutta la flessibilità di cui potresti aver bisogno.

Se la risposta è no (tornando alla domanda iniziale), allora penso che tu possa vivere con il modello n. 1 (fai la cosa più semplice che potrebbe funzionare).

Ora, riguardo alle domande bonus:

  • Qual è il posto migliore per definire le varie configurazioni condivise come nel controllo del codice sorgente, nelle directory di distribuzione, nei plugin comuni ecc. (Sto assumendo il genitore ma sono stato spesso morso da questo e sono finiti in ogni progetto piuttosto che uno comune).

Onestamente, non so come non dare una risposta generale qui (come "usa il livello in cui pensi abbia senso ricambiare le cose"). E comunque, i pon pon possono sempre ignorare le impostazioni ereditate.

  • In che modo il plug-in di rilascio Maven, Hudson e Nexus affrontano il modo in cui hai impostato i tuoi multi-progetti (forse una domanda gigantesca, è più se qualcuno è stato sorpreso quando da come è stata creata una build multi-progetto)?

L'impostazione che utilizzo funziona bene, niente di particolare da menzionare.

In realtà, mi chiedo come il plugin di rilascio di maven affronti il ​​modello n. 1 (specialmente con la <parent>sezione poiché non è possibile avere dipendenze SNAPSHOT al momento del rilascio). Sembra un problema con pollo o uova, ma non riesco a ricordare se funziona ed era troppo pigro per testarlo.


È molto bello come posso vedere come si ridimensiona. Lo svn: externals risponde alla mia preoccupazione per il fatto di essere ingombrante.
Jamie McCrindle,

@jamie Sono contento che lo trovi utile.
Pascal Thivent,

1
Potresti approfondire come far funzionare il "hack"? Ho il progetto Trunks e prevedo che scegli l'opzione -pl con "avvio di una build del reattore" ma questo si presenta come un problema quando si esegue una versione della struttura perché questa opzione non passa da una build a livello di root posso inserirlo nell'opzione <argomenti /> del plugin di rilascio. Pertanto il rilascio: eseguire failes perché cerca di lavoro sul pom-livello principale ...
Jan

L'hack svn: externals è l'hack svn più utile che abbia mai visto da molto tempo. Molto utile con progetti che hanno diramazioni per progetto all'interno dello stesso repository.
omerkudat,

1
Ciao Pascal, come gestiresti la versione # se i progetti menzionati nella sezione dei moduli non usano parent-pom come <parent> ma some-other-project-parent-pom? Quali versioni # otterremo per un manufatto di tali progetti (versione # del manufatto nella sezione <parent> di quei progetti O versione # del Progetto che elenca questi progetti come moduli)? stackoverflow.com/questions/25918593/…
AKS

34

Dalla mia esperienza e dalle migliori pratiche di Maven ci sono due tipi di "genitori"

  • Pom padre "azienda": questo pom contiene informazioni e configurazioni specifiche della tua azienda che ereditano ogni pom e non devono essere copiate. Queste informazioni sono:

    • repository
    • sezioni di gestione della distribuzione
    • configurazioni comuni di plug-in (come le versioni sorgente e target di maven-compilatore-plug-in)
    • organizzazione, sviluppatori, ecc

    La preparazione di questo pom padre deve essere eseguita con cautela, poiché tutti i pom della tua azienda erediteranno da esso, quindi questo pom deve essere maturo e stabile (il rilascio di una versione del pom padre non dovrebbe influire sul rilascio di tutti i progetti della tua azienda!)

  • il secondo tipo di genitore pom è un genitore multimodulo. Preferisco la tua prima soluzione: questa è una convenzione predefinita maven per progetti multi modulo, molto spesso rappresenta la struttura del codice VCS

L'intenzione è di essere scalabile su una build su larga scala, quindi dovrebbe essere scalabile su un gran numero di progetti e artefatti.

I progetti multipli hanno una struttura ad albero, quindi non sei ridotto a un livello di pom padre. Prova a trovare una struttura di progetto adatta alle tue esigenze: un classico esempio è come eliminare i progetti di mutimodulo

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

Alcune domande bonus:

  • Qual è il posto migliore per definire le varie configurazioni condivise come nel controllo del codice sorgente, nelle directory di distribuzione, nei plugin comuni ecc. (Sto assumendo il genitore ma sono stato spesso morso da questo e sono finiti in ogni progetto piuttosto che uno comune).

Questa configurazione deve essere saggiamente suddivisa in una società madre "pom" padre e progetto padre padre (i). Le cose relative a tutto il tuo progetto vanno al genitore "azienda" e ciò relativo al progetto corrente va al progetto.

  • In che modo il plug-in di rilascio Maven, Hudson e Nexus affrontano il modo in cui hai impostato i tuoi multi-progetti (forse una domanda gigantesca, è più se qualcuno è stato sorpreso quando da come è stata creata una build multi-progetto)?

Il padre principale dell'azienda deve essere rilasciato per primo. Per i multiprogetti si applicano le regole standard. Il server CI deve sapere tutto per costruire correttamente il progetto.


1
In modo che ci siano due tipi di progetti genitori / poms. Uno senza declareazione <moduli>. Questo è quello usato per l'ereditarietà. E un progetto genitore con la dichiarazione <multimodule>. Questo è quello che i sottomoduli non ereditano, è solo per gestire la costruzione del progetto di attesa. Ho ragione ?
Lisbona

22
  1. Un genitore indipendente è la migliore pratica per condividere la configurazione e le opzioni tra componenti altrimenti non accoppiati. Apache ha un progetto pom padre per condividere note legali e alcune opzioni di packaging comuni.

  2. Se il tuo progetto di livello superiore ha un vero lavoro al suo interno, come l'aggregazione di javadoc o il confezionamento di una versione, allora avrai conflitti tra le impostazioni necessarie per fare quel lavoro e le impostazioni che desideri condividere tramite genitore. Un progetto per soli genitori lo evita.

  3. Un modello comune (ignorando il numero 1 per il momento) è che i progetti con codice utilizzino un progetto padre come loro padre e utilizzino il livello principale come padre. Ciò consente a tutti gli elementi fondamentali di essere condivisi da tutti, ma evita il problema descritto nel n. 2.

  4. Il plug-in del sito diventerà molto confuso se la struttura padre non è la stessa della struttura di directory. Se vuoi costruire un sito aggregato, dovrai fare un po 'di confusione per aggirare questo.

  5. Apache CXF è un esempio del modello in # 2.


2
Ho dato un'occhiata a ibilio e molti progetti sembrano preferire il genitore "indipendente". Hibernate, ActiveMQ, Jetty, XStream ecc. Il che suggerisce che è il meccanismo defacto.
Jamie McCrindle,

2
Un altro aspetto negativo del genitore indipendente sembra essere il plug-in di rilascio di Maven che desidera che il genitore venga bloccato su una versione prima che esegua un rilascio. Probabilmente non è un grosso problema dato che il genitore non dovrebbe cambiare troppo.
Jamie McCrindle,

9

C'è un piccolo problema con il terzo approccio. Poiché i POM aggregati (myproject / pom.xml) di solito non hanno affatto un genitore, non condividono la configurazione. Ciò significa che tutti quei POM aggregati avranno solo repository predefiniti.

Questo non è un problema se si utilizzano solo plug-in da Central, tuttavia, ciò non funzionerà se si esegue un plug-in utilizzando il plug-in: formato obiettivo dal proprio repository interno. Ad esempio, puoi avere foo-maven-plugincon il groupId di org.examplefornire l'obiettivo generate-foo. Se si tenta di eseguirlo dalla radice del progetto utilizzando il comando like mvn org.example:foo-maven-plugin:generate-foo, non verrà eseguito sui moduli aggregati (vedere la nota di compatibilità ).

Sono possibili diverse soluzioni:

  1. Distribuire il plugin su Maven Central (non sempre possibile).
  2. Specifica la sezione del repository in tutti i POM aggregati (interrompe il DRY principio ).
  3. Configurare questo repository interno in settings.xml (nelle impostazioni locali in ~ / .m2 / settings.xml o nelle impostazioni globali in /conf/settings.xml). La creazione fallirà senza quei settings.xml (potrebbe essere OK per grandi progetti interni che non dovrebbero mai essere realizzati al di fuori dell'azienda).
  4. Usa il genitore con le impostazioni dei repository nei tuoi POM aggregati (potrebbero essere troppi POM dei genitori?).
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.