2009-09-21 8 views
31

Abbiamo un grande sistema Java (> 500.000 LOC) che dipende dai pacchetti 40-50 OSS . Il sistema è compilato con Ant e la gestione delle dipendenze è attualmente gestita manualmente. Sto indagando su Ivy e/o Maven su dipendenze automatiche. L'anno scorso abbiamo esaminato Maven come sistema di automazione delle build e l'abbiamo rifiutato perché richiederebbe totalmente la ristrutturazione di per far corrispondere l'architettura di Maven al nostro sistema. Ora sono cercando di automatizzare solo le attività di gestione delle dipendenze.Gestione grande dipendenza sistema Java

Ho fatto qualche esperimento con Ivy ma ho avuto problemi. Per esempio, quando ho specificare ActiveMQ come una dipendenza, e dico Ivy per utilizzare le POM nel repository Maven per la specifica dipendenza, Ivy recupera un mucchio di pacchetti (Jetty, Derby e Geronimo per esempio), che io sappia aren' t necessario semplicemente usare ActiveMQ.

Se ho impostato usepoms = "false" in ivysettings.xml recupera solo activemq.jar, ma che sembra sconfiggere lo scopo di Ivy e relega ad un semplice vaso-Fetcher con manualmente costruite dipendenza specifiche .

C'è un grosso problema qui, quello che si chiamava "DLL Hell" in Windows. In alcuni casi, due dipendenze dirette di primo livello corrisponderanno a a versioni diverse della stessa dipendenza transitiva (per l'istanza log4j.jar ). Solo un log4j.jar può trovarsi nel classpath, quindi la risoluzione delle dipendenze da implica la determinazione manuale della versione compatibile con tutti i suoi client nel nostro sistema.

Credo che tutto si riduce alla qualità della dipendenza specifiche di ogni pacchetto (POM). Nel caso di ActiveMQ, non ci sono dichiarazioni dello , quindi qualsiasi riferimento ad ActiveMQ scaricherà tutte le sue dipendenze a meno che non escludiamo manualmente quelle che sappiamo non vogliamo .

Nel caso di log4j, la risoluzione automatica delle dipendenze richiederebbe che tutti i clienti di log4j (altri pacchetti che dipendono da log4j) validate contro tutte le versioni precedenti di log4j e forniscono una gamma (o lista) delle versioni log4j compatibili nel POM. Probabilmente è lo stesso molto da chiedere.

È questa la situazione attuale o mi manca qualcosa?

+8

+1 per una chiara descrizione del problema con le soluzioni tentate. Spero tu abbia una buona risposta. –

+2

Le prime 4 risposte in uscita offrono tutte una prospettiva preziosa. Kevin's è conciso e preciso. Robert e Rich forniscono molti più dettagli. Vladimir contribuisce con un'opinione positiva basata sull'esperienza del mondo reale. I quattro insieme mi aiutano a stabilire le mie aspettative e indicano la via per risolvere il problema. Mi piacerebbe "accettare" tutte e quattro le risposte, ma SO non lo consente. Sto dando l'accettazione a Robert Munteanu perché era il primo ad avere una risposta dettagliata. –

risposta

11

Hai perfettamente ragione nel dire che

Immagino che tutto si riduca alla qualità delle specifiche di dipendenza di ciascun pacchetto (il POM).

L'unica cosa che vorrei aggiungere è visualizzare il POM, o qualsiasi altra forma di metadati, come punto di partenza. È abbastanza utile che ad es. ActiveMQ fornisce tutte le dipendenze per te, ma spetta a te scegliere se effettivamente si adatta al tuo progetto.

Dopo tutto, anche prendendo in considerazione la versione di log4j, avresti una dipendenza esterna scegliere la versione o scegliere la versione che sai funzionare per voi?


Quanto a come si può scegliere di dipendenze su misura, ecco cosa si può fare con Ivy:

pacchetti non necessari

Ivy recupera un mucchio di pacchetti (Jetty, Derby e Geronimo per esempio) che so non sono necessari per usare solo ActiveMQ.

Questo di solito accade a causa della scarsa modularità nell'applicazione. Una parte del l'applicazione ha bisogno Jetty per esempio, ma si finisce con questa dipendenza transitiva, anche se non ne fanno uso.

probabilmente avrete bisogno di guardare negli ivy exclude mechanism:

<dependency name="A" rev="1.0"> 
    <exclude module="B"/> 
</dependency> 

versioni di dipendenza

solo log4j.jar può essere nel classpath, in modo da dipendenza risoluzione consiste nel determinare manualmente la versione è compatibile con tutti i suoi clienti nel nostro sistema.

Forse sto travisamento questo, ma non c'è manuale elemento nella risoluzione dei conflitti di Ivy. C'è un elenco di default conflict managers:

  • tutto: questo conflitto conflitti direttore di risolvere per via di selezionando tutte le revisioni. Chiamato anche NoConflictManager, sfrutta qualsiasi modulo.
  • ultima volta: questo manager conflitto seleziona solo la revisione 'ultima', ultimo dei quali è definito come l'ultimo di tempo. Nota che l'ultima volta è costoso da calcolare, quindi se preferisci, preferisci l'ultima revisione.
  • ultima revisione: questo manager conflitto seleziona solo la revisione 'ultima', ultimo dei quali è definito da un confronto tra stringhe di revisioni.
  • ultima compatibile: questo manager conflitto seleziona la versione più recente nei conflitti che può risultare in un insieme compatibile di dipendenze. Ciò significa che alla fine questo gestore di conflitti non consente alcun conflitto (come lo strict conflict manager), tranne che segue una strategia di best effort per cercare di trovare un insieme di moduli compatibili (in base ai vincoli di versione);
  • rigorosa: questo manager conflitto genera un'eccezione (cioè provoca un errore di generazione) ogni volta che si trova un conflitto.

Se necessario, è possibile provide your own conflict manager.

-5

"E 'questo lo stato attuale delle cose"

Sì.

Questo è il compromesso open source.

Un quadro closed-source (cioè, .Net) risolverà tutto questo per voi.

una soluzione open source significa che dovete risolverlo (e risolverlo) per tutto il tempo.

Potreste essere in grado di trovare alcune configurazioni pre-costruito e pagare qualcuno per mantenere quelli up-to-date. Ad esempio, è possibile scegliere di utilizzare Red Hat Enterprise Linux. Se ti attieni precisamente a ciò che supportano (e nulla più), allora la configurazione viene risolta.

Le probabilità sono buone, tuttavia, nessuna configurazione pacchettizzata soddisfa i requisiti dell'utente.

+2

Non sono assolutamente d'accordo con la vostra closed-source è meglio, l'open-source sta investendo lo sforzo costantemente. Hai un'alternativa closed-source a questo problema? Tranne .NET. –

+1

Non sono d'accordo che questo è lo stato delle cose. Le dipendenze in questione sono opzionali e gestite correttamente in Maven (vedi la mia risposta per maggiori dettagli). Può darsi che Ivy non sia in grado di gestire la proprietà facoltativa, ma ha comunque un mezzo per gestire tali dipendenze. Quindi, qual è la tua base per fare questo reclamo? –

+0

@Robert Munteanu: Non ho detto che una soluzione closed-source era migliore in un modo vago e generale. Fornisce componenti pre-integrati. Questo è * solo * vantaggio. E la maggior parte delle volte, è in realtà una responsabilità perché le cose pre-integrate si evolvono lentamente e restano indietro rispetto allo stato dell'arte. –

4

Penso che questo sia davvero lo stato attuale delle cose. OSGi e il nuovo sistema di pacchettizzazione proposto per java 1.7 (la discussione su quello giunge a una conclusione già?) Sono tentativi di correggere almeno il problema delle versioni diverse di una libreria, ma io non pensa che saranno in grado di risolvere il tuo problema adesso.

+0

avete qualche link con maggiori informazioni su "il nuovo sistema di packaging proposto per java 1.7"? –

+0

Stavo pensando a JSR 277: http://jcp.org/en/jsr/detail?id=277 - google per molte opinioni ;-) ... I _thought_ era destinato a entrare in 1.7 ma apparentemente non succederà. –

2

"È questo lo stato attuale delle cose?"

Non con OSGi. Si consiglia di esaminare i contenitori e i bundle OSGi. Un pacchetto è simile a un file jar, ma supporta metadati che dettagliano la sua versione e le versioni dei pacchetti correlati necessari (inserendo gli attributi nel file META-INF). Quindi il tuo bund4 log4j indicherà la sua versione, ei bundle dipendenti descriveranno in dettaglio le versioni di log4j che richiedono.

Inoltre, è supportato un meccanismo di caricamento classi non gerarchico, in modo che sia possibile caricare più versioni di log4j, e bundle diversi possono specificare e associare a tali versioni diverse.

Javaworld ha un'ottima introduzione here.

5

Questo è praticamente tutto. Il sistema di dipendenze del maven (che Ivy segue più o meno) lascia ai singoli progetti di fare un buon lavoro aggiungendo i metadati necessari per le loro dipendenze. La maggior parte non lo fa.

Se segui questa strada, aspettati di dedicare tempo alla configurazione delle esclusioni.

Per i manifesti raccomandando OSGi, l'OP ha detto che non è disposto a ri-architetto il suo sistema di compilazione per Maven, io non credo che vorrebbe re-architetto sua applicazione per essere compatibile OSGi. Inoltre, un sacco di progetti OSS che sono compatibili OSGi (e non ci sono tanti come ci si spera) ha metadati come cattivo o peggio che in Maven

+0

Penso che dire "La maggior parte non lo è" è un'esagerazione grossolana, puoi citare effettivamente tutti i principali progetti che sono mal configurati? La stragrande maggioranza dei progetti Maven che ho usato sono ben educati. È più vero che la maggior parte degli utenti non capisce tutte le sfumature del sistema e viene inciampato da loro. Può ancora essere un problema se gli utenti non utilizzano RTFM, ma è sempre il caso di sistemi complessi. –

+0

Ivy non "segue per lo più" il sistema di dipendenza Maven, ha semplicemente un sistema di adattatori per esso. È vero, le POM importate da Maven fanno schifo, ma se si prende il tempo per ripristinare manualmente le impostazioni di dipendenza per Ivy, in realtà si finisce con qualcosa di molto meglio che Maven potrebbe mai fornire. – Esko

+0

@Rich Oltre che ActiveMQ annotato dall'OP? Ho riscontrato problemi con CXF che non dichiaravano correttamente le dipendenze come "facoltativo" o altrimenti non necessario. – Kevin

5

Delle dipendenze elencate, le seguenti sono definite come optional nel pom activemq-core (vedere anche relevant section dal libro Maven).

  • org.apache.derby: derby
  • org.apache.geronimo.specs: geronimo-jta_1.0.1B_spec

non ho visto una dipendenza diretta sul molo, quindi potrebbe essere temporaneamente incluso da una delle dipendenze opzionali.

In Maven dipendenze opzionali vengono gestiti automaticamente. Essenzialmente qualsiasi dipendenza dichiarata facoltativa deve essere dichiarata nel pom per essere utilizzata.Dalla documentazione collegata sopra:

Le dipendenze opzionali vengono utilizzate quando non è realmente possibile (per qualsiasi motivo) dividere un progetto in sottomoduli. L'idea è che alcune delle dipendenze vengono utilizzate solo per determinate funzionalità nel progetto e non saranno necessarie se tale funzione non viene utilizzata. Idealmente, una tale funzionalità sarebbe suddivisa in un sottomodulo che dipendeva dal progetto di funzionalità di base ... questo nuovo sottoprogetto avrebbe solo dipendenze non opzionali, dal momento che avresti bisogno di tutte se avessi deciso di utilizzare la funzionalità del sottoprogetto.

Tuttavia, poiché il progetto non può essere suddiviso (di nuovo, per qualsiasi motivo), queste dipendenze sono dichiarate facoltative. Se un utente desidera utilizzare funzionalità correlate a una dipendenza opzionale, dovrà dichiarare la dipendenza opzionale nel proprio progetto. Questo non è il modo più chiaro per gestire questa situazione, ma di nuovo entrambe le dipendenze opzionali e le esclusioni di dipendenza sono soluzioni stop-gap.

Non sono sicuro se è possibile configurare Ivy per ignorare le dipendenze opzionali, ma è possibile configurarlo su exclude dependencies. Ad esempio:

<dependency name="A" rev="1.0"> 
    <exclude module="B"/> 
</dependency> 

Questo non è del tutto soddisfacente, lo so. Può darsi che Ivy supporti dipendenze opzionali (avrò un ulteriore aspetto e aggiornamento se trovo qualcosa), ma il meccanismo di esclusione ti consente almeno di gestirli.


Riguardo l'ultima parte della domanda. Maven risolverà le versioni delle dipendenze per log4j e se le versioni sono compatibili selezionerà automaticamente il "più vicino" delle versioni elencate.

Dal Introduction to the Dependency Mechanism:

  • Dipendenza mediazione - Determina quale verrà utilizzata la versione di una dipendenza quando si incontrano più versioni di un artefatto. Attualmente, Maven 2.0 supporta solo l'uso della "definizione più vicina", il che significa che utilizzerà la versione della dipendenza più vicina al progetto nell'albero delle dipendenze. Puoi sempre garantire una versione dichiarandola esplicitamente nel tuo POM del progetto. Si noti che se due versioni di dipendenza sono alla stessa profondità nell'albero delle dipendenze, fino a quando Maven 2.0.8 non è stato definito quale vincerebbe, ma poiché Maven 2.0.9 è l'ordine nella dichiarazione che conta: la prima dichiarazione vince.

    • "definizione più vicina" significa che la versione utilizzata sarà la più vicina al progetto nell'albero delle dipendenze, ad es. se le dipendenze per A, B e C sono definite come A -> B -> C -> D 2.0 e A -> E -> D 1.0, allora D 1.0 verrà usato quando si costruisce A perché il percorso da A a D attraverso E è più corto. Si potrebbe aggiungere una dipendenza esplicitamente a D 2.0 in A per forzare l'uso di D 2,0

Se le versioni non sono compatibili hai un problema più grande di quanto la dipendenza risoluzione. Credo che Ivy operi su un modello simile ma non sono esperto.

3

Attualmente sto utilizzando Ivy per gestire più di 120 OSS e librerie proprietarie per diversi progetti (alcuni autonomi, alcuni dipendenti). Nel 2005 (quando Ivy era ancora di Jayasoft) ho deciso (o dovuto) di scrivere i file ivy.xml per ogni pacchetto integrato.

Il più grande vantaggio è che ho il pieno controllo sulle varie configurazioni. Questo può sembrare eccessivo per alcuni, ma il nostro sistema di compilazione ha funzionato in modo affidabile per oltre 4 anni e aggiungere una nuova libreria è in genere un lavoro di 5 minuti.

0

C'è tutta l'idea dell'iniezione di dipendenza, che invariabilmente porterà al programma che deve essere ristrutturato. Ho sentito un po 'di rumore su GUICE essere bravi in ​​questo senso. Nella prospettiva della distribuzione ho avuto un discreto successo con la distribuzione di solo .jar che abbiamo creato con dipendenza .jars che viene recuperato dai progetti originali tramite jnlp. Il sistema di generazione dietro a questo ha comportato il tracciamento manuale delle nuove versioni delle dipendenze e l'aggiornamento nel sistema di generazione.