30 votes

Gestion des dépendances d'un grand système Java

Nous avons un grand système Java (>500 000 LOC) qui dépend de 40-50 paquets OSS. . Le système est construit à l'aide de Ant, et la gestion des dépendances est est actuellement gérée manuellement. Je suis en train d'étudier Ivy et/ou Maven pour automatiser les dépendances. Nous avons étudié Maven comme système d'automatisation d'automatisation de la construction l'année dernière et l'avons rejeté parce qu'il nécessitait une restructuration totale de l'application. restructurer notre système pour l'adapter à l'architecture de Maven. Maintenant, je Je cherche maintenant à automatiser uniquement les tâches de gestion des dépendances.

J'ai fait quelques expériences avec Ivy mais j'ai rencontré des problèmes. Par exemple, lorsque je spécifie ActiveMQ comme dépendance, et que je demande à Ivy de d'utiliser les POMs dans le référentiel Maven pour la spécification des dépendances, Ivy Ivy récupère un tas de paquets (Jetty, Derby et Geronimo par exemple) qui par exemple) dont je sais qu'ils ne sont pas nécessaires pour utiliser ActiveMQ.

Si je définis usepoms="false" dans ivysettings.xml, il récupère seulement activemq.jar, mais cela semble aller à l'encontre du but d'Ivy et le et le relègue à un simple récupérateur de bocaux avec des spécifications de dépendances spécifications.

Il y a un plus gros problème ici, ce qu'on appelait "l'enfer des DLL" sous Windows. Dans certains cas, deux dépendances directes de premier niveau vont pointeront vers différentes versions de la même dépendance transitive (par exemple exemple log4j.jar). Un seul log4j.jar peut se trouver dans le classpath. la résolution des dépendances implique de déterminer manuellement quelle version est compatible avec tous ses clients dans notre système.

Je pense que tout se résume à la qualité de la spécification des dépendances de chaque paquet de chaque paquet (le POM). Dans le cas d'ActiveMQ, il n'y a pas de déclarations de portée de scope, donc toute référence à ActiveMQ téléchargera toutes ses dépendances dépendances, à moins que nous n'excluions manuellement celles que nous ne voulons pas que nous ne voulons pas.

Dans le cas de log4j, la résolution automatique des dépendances nécessiterait que tous les clients de log4j (les autres paquets qui dépendent de log4j) valident contre toutes les versions antérieures de log4j et fournissent un éventail (ou une liste) de versions compatibles de log4j dans le POM. C'est probablement trop trop demander.

Est-ce l'état actuel des choses, ou est-ce que je rate quelque chose ?

11voto

Robert Munteanu Points 31558

Vous avez absolument raison de dire que

Je pense que tout se résume à la qualité de la spécification des dépendances de chaque paquet (le POM).

La seule chose que j'ajouterais est de considérer le POM, ou toute autre forme de métadonnées, comme un point de départ. Il est très utile que, par exemple, ActiveMQ fournisse toutes les dépendances pour vous, mais c'est à vous de choisir si cela convient vraiment à votre projet.

Après tout, même en tenant compte de la version de log4j, voudriez-vous qu'une dépendance externe choisisse la version ou choisir la version que vous savez fonctionner pour vous ?


Quant à la façon dont vous pouvez choisir de personnaliser les dépendances, voici ce que vous pouvez faire avec Ivy :

Paquets inutiles

Ivy récupère un tas de paquets (Jetty, Derby et Geronimo par exemple) dont je sais qu'ils ne sont pas nécessaires pour utiliser ActiveMQ.

Cela se produit généralement en raison d'une mauvaise modularité de l'application. Une partie de l'application a besoin de Jetty par exemple, mais vous vous retrouvez avec cette dépendance transitive même si vous ne l'utilisez pas.

Vous voudrez probablement vous pencher sur le mécanisme d'exclusion du lierre :

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

Versions de dépendances

Un seul log4j.jar peut se trouver dans le classpath, de sorte que la résolution des dépendances implique de déterminer manuellement quelle version est compatible avec tous ses clients dans notre système.

Peut-être que je lis mal, mais il n'y a pas de manuel dans la résolution des conflits d'Ivy. Il existe une liste de gestionnaires de conflits par défaut :

  • todo : ce gestionnaire de conflits résout les conflits en sélectionnant toutes les révisions. Aussi appelé NoConflictManager, il n'expulse aucun module.
  • dernier-temps Ce gestionnaire de conflits sélectionne uniquement la "dernière" révision, la dernière étant définie comme la plus récente dans le temps. Notez que le calcul de la dernière révision dans le temps est coûteux, préférez donc la dernière révision si vous le pouvez.
  • dernière révision Ce gestionnaire de conflits sélectionne uniquement la "dernière" révision, la dernière étant définie par une comparaison de chaînes de révisions.
  • dernière version compatible ce gestionnaire de conflits sélectionne la dernière version dans les conflits qui peuvent aboutir à un ensemble de dépendances compatibles. Cela signifie qu'en fin de compte, ce gestionnaire de conflits ne permet aucun conflit (comme le gestionnaire de conflits strict), sauf qu'il suit une stratégie du meilleur effort pour essayer de trouver un ensemble de modules compatibles (selon les contraintes de version) ;
  • strict ce gestionnaire de conflits lève une exception (c'est-à-dire qu'il provoque un échec de la construction) chaque fois qu'un conflit est trouvé.

Si nécessaire, vous pouvez fournir votre propre gestionnaire de conflits .

5voto

Kevin Points 19613

C'est à peu près tout. Le système de dépendance maven (qu'Ivy suit plus ou moins) laisse le soin aux projets individuels de faire un bon travail en ajoutant les méta-données nécessaires pour leurs dépendances. La plupart ne le font pas.

Si vous choisissez cette voie, attendez-vous à passer du temps à définir des exclusions.

Pour les posters recommandant OSGi, le PO a dit qu'il n'est pas prêt à ré-architecturer son système de construction pour Maven, je ne pense pas qu'il veuille ré-architecturer son système de construction pour Maven. application pour être conforme à l'OSGi. De plus, de nombreux projets OSS conformes à OSGi (et il n'y en a pas autant qu'on pourrait l'espérer) ont des métadonnées aussi mauvaises, voire pires, que celles de Maven.

5voto

Rich Seller Points 46052

Parmi les dépendances que vous énumérez, les suivantes sont définies en tant que optional dans le activemq-core pom (voir aussi le section pertinente du livre Maven).

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

Je n'ai pas vu de dépendance directe sur Jetty, il est donc possible qu'il soit inclus de manière transitive à partir de l'une des dépendances optionnelles.

Dans Maven, les dépendances optionnelles sont gérées automatiquement. Essentiellement, toute dépendance déclarée optionnelle doit être redéclarée dans votre pom pour être utilisée. Extrait de la documentation mentionnée ci-dessus :

Les dépendances optionnelles sont utilisées lorsqu'il n'est pas vraiment possible (pour une raison quelconque) de diviser un projet en sous-modules. L'idée est que certaines dépendances ne sont utilisées que pour certaines fonctionnalités du projet, et ne seront pas nécessaires si cette fonctionnalité n'est pas utilisée. Idéalement, une telle fonctionnalité serait divisée en un sous-module qui dépendrait du projet de fonctionnalité de base... ce nouveau sous-projet n'aurait que des dépendances non-optionnelles, puisque vous en auriez besoin si vous décidiez d'utiliser la fonctionnalité du sous-projet.

Cependant, comme le projet ne peut pas être scindé (encore une fois, pour une raison quelconque), ces dépendances sont déclarées facultatives. Si un utilisateur souhaite utiliser une fonctionnalité liée à une dépendance optionnelle, il devra redéclarer cette dépendance optionnelle dans son propre projet. Ce n'est pas la façon la plus claire de gérer cette situation, mais là encore, les dépendances optionnelles et les exclusions de dépendances sont des solutions provisoires.

Je ne suis pas sûr que vous puissiez configurer Ivy pour qu'il ignore les dépendances optionnelles, mais vous pouvez le configurer pour exclure les dépendances . Par exemple :

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

Ce n'est pas entièrement satisfaisant, je sais. Il se peut qu'Ivy supporte les dépendances optionnelles (je vais regarder de plus près et mettre à jour si je trouve quelque chose), mais le mécanisme d'exclusion vous permet au moins de les gérer.


Concernant la dernière partie de votre question. Maven résoudra les versions de dépendance pour log4j et si les versions sont compatibles, il sélectionnera automatiquement la plus proche des versions listées.

De la Introduction au mécanisme de dépendance :

  • Médiation des dépendances - elle détermine quelle version d'une dépendance sera utilisée lorsque plusieurs versions d'un artefact sont rencontrées. Actuellement, Maven 2.0 ne supporte que l'utilisation de la "définition la plus proche", ce qui signifie qu'il utilisera la version de la dépendance la plus proche de votre projet dans l'arbre des dépendances. Vous pouvez toujours garantir une version en la déclarant explicitement dans le POM de votre projet. Notez que si deux versions de dépendances sont à la même profondeur dans l'arbre des dépendances, jusqu'à Maven 2.0.8 il n'était pas défini laquelle l'emporterait, mais depuis Maven 2.0.9 c'est l'ordre dans la déclaration qui compte : la première déclaration l'emporte.

    • "définition la plus proche" signifie que la version utilisée sera la plus proche de votre projet dans l'arbre des dépendances, par exemple, si les dépendances pour A, B et C sont définies comme A -> B -> C -> D 2.0 et A -> E -> D 1.0, alors D 1.0 sera utilisée lors de la construction de A car le chemin de A à D en passant par E est plus court. Vous pourriez ajouter explicitement une dépendance à D 2.0 dans A pour forcer l'utilisation de D 2.0

Lorsque les versions ne sont pas compatibles, vous avez un problème plus important que la résolution des dépendances. Je crois qu'Ivy fonctionne sur un modèle similaire mais je ne suis pas un expert.

4voto

Simon Groenewolt Points 7046

Je pense que c'est effectivement l'état actuel des choses. OSGi et le nouveau système d'empaquetage proposé pour java 1.7 (les discussions à ce sujet ont-elles déjà abouti ?) sont des tentatives pour résoudre au moins le problème de la dépendance à l'égard de différentes versions d'une bibliothèque, mais je ne pense pas qu'ils seront en mesure de résoudre votre problème pour le moment.

2voto

Brian Agnew Points 143181

"Est-ce l'état actuel des choses ?"

Pas avec OSGi. Vous pouvez vous intéresser aux conteneurs et aux bundles OSGi. Un bundle est comme un fichier jar, mais il supporte des méta-données détaillant sa version, et les versions des bundles liés qu'il requiert (en mettant des attributs dans le fichier META-INF). Ainsi, votre bundle log4j indiquera sa version, et les bundles dépendants détailleront les versions de log4j dont ils ont besoin.

En outre, un mécanisme de chargeur de classe non hiérarchique est pris en charge, de sorte que vous pouvez charger plusieurs versions de log4j, et différents bundles peuvent spécifier et se lier à ces différentes versions.

Javaworld a une très bonne introduction aquí .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X