2010-12-14 8 views
5

Nous avons plusieurs applications qui utilisent Apache HTTPClient 3 pour faire des requêtes HTTP. Récemment, nous avons également commencé à créer des clients de services Web qui utilisent HTTPClient 4 pour diverses raisons. La position Apache est que "versions majeures ne sont pas rétro-compatibles". Bien que j'aimerais mettre à jour tous nos projets pour utiliser la version 4, ce n'est tout simplement pas faisable.accès multiples versions d'un package en Java

Ainsi, alors que ma principale question est plutôt générale, ma question est particulièrement. Comment puis-je utiliser HTTPClient version 3 et 4 dans la même application? Dans notre cas, une application peut être une application Web, de bureau ou de ligne de commande.

J'ai lu le SO question for java-dynamically-load-multiple-versions-of-same-class qui semble demi proche, mais je ne me soucie pas tant de la partie dynamique. En fait, je voudrais que les JAR soient livrés avec l'application (exemple, WEB-INF/lib pour les applications web). Je vois aussi OSGi beaucoup dans des questions similaires à celui-ci mais il semble être trop compliqué ou peut-être trop complexe (peut-être un exemple simple pourrait prouver le contraire).

En fin de compte, je veux être en mesure de remettre une équipe un ensemble de pots qu'ils peuvent déposer et il fonctionne juste indépendamment de leur projet à l'aide du client HTTP 3.

+1

Il s'agit d'un cas où la gouvernance architecturale aurait été une bonne idée: prendre la décision de rester avec la version 3 ou tout déplacer vers la version 4. Maintenant, vous devez payer des coûts d'implémentation pour une solution patchwork. empirer au fil du temps. – Anon

+1

@Anon: Pas d'offense mais sans connaître la situation, je ne conseillerais pas de faire une telle déclaration générale. J'ai dit "pour diverses raisons" pour éviter de tels commentaires. –

+0

OSGi au moins fonctionne (vous devez décider si c'est exagéré ou non), je ne connais pas de façon triviale de le faire autre que d'avoir deux serveurs Web, un pour chaque version de la bibliothèque. –

Répondre

5

Comme d'autres l'ont indiqué, vous pouvez créer plusieurs chargeurs de classe et charger les deux versions isolément. Cette partie est assez facile. Le problème est que cela divise essentiellement votre "espace de classe", et il sera toujours très difficile de se référer à la v3 à partir de certaines parties de votre application tout en faisant référence à la v4 d'autres parties de votre application. Vous devrez partitionner votre application très soigneusement ... alors pourquoi ne pas le partager et livrer deux applications?

OSGi pourrait être une solution si vous êtes capable de factoriser la fonctionnalité dans les services.Mais convertir une application héritée en OSGi n'est pas quelque chose à prendre à la légère, et ce ne sera certainement pas une évasion bon marché du piège dans lequel vous êtes entré. Je dis cela en tant qu'auteur d'un livre sur OSGi et un évangéliste OSGi bien connu. Un objectif à long terme de conversion de vos applications en OSGi serait vous apporter de grands avantages, mais impliquera également des coûts initiaux importants.

1

Utilisez les chargeurs de classes multiples, un pour chaque Client HTTP que vous souhaitez adopter.

La façon la plus simple est d'étendre URLClassLoader et pirater à la hardcode classpath pour chaque version séparément. Ensuite, vous devez juste vous assurer que le reste du code sait quelle version du client HTTP utiliser (et accède au chargeur de classe correct pour y accéder).

+0

Comment cela fonctionnerait-il pour une webapp où les JAR doivent être livrés avec les WARs? –

+0

Vous envoyez toutes les versions de chaque bibliothèque référencée, mais placez-les ailleurs que web-inf/lib. Votre chargeur de classe personnalisé regarde dans l'emplacement «quelque part autre». Cela empêche le conteneur de guerre de les référencer directement. –

1

Vous devez utiliser les chargeurs de classes séparées pour v3 et v4. Placez les fichiers v3 et v4 dans des dossiers distincts au-delà du chemin de classe de votre application. Utilisez URLClassLoadedr pour charger chacune des versions. L'URL que vous transmettez à chacun des chargeurs de classe doit contenir l'URL de la version spécifique du client HTTP.

Mais je vous donner un conseil? Vérifiez d'abord que vous avez vraiment besoin de tout cela avant de commencer. C'est vrai que les versions pourraient être incompatibles. Mais il y a une grande chance qu'ils le soient.

+1

Je pense que vous voulez dire "énorme chance qu'ils sont * pas *" Je sais HTTP Client v3 et V4 ne jouent pas bien ensemble. –

2

Une solution simple mais simple serait que vous obtenez les sources pour HttpClient3 et HttpClient4, et factoriser les noms de paquets à quelque chose comme

org.apache.commons.httpclient3 pour HttpClient3 et org.apache.commons .httpclient4 pour HttpClient4 pour éviter la collision. Puis compilez, empaquetez, faites.

Maintenant, il est facile de basculer entre les deux implémentations et elles ne se heurtent pas dans le chargeur de classe.

+1

Bien que cela fonctionne pour un pot, il crée plus de problèmes qu'il résout. Vous pourriez avoir besoin d'apache.commons.logging par exemple, et les deux versions dépendront des différentes versions de la journalisation des communs (puisqu'elles ont été publiées à des moments différents). Vous pouvez maintenant réorganiser la journalisation des communs de la manière ci-dessus, mais vous devez ensuite revenir en arrière et éditer manuellement tout le code source dans les clients http reconditionnés pour référencer correctement. Bientôt, une telle solution devient un gros gâchis. –

+1

Est-ce qu'ils dépendent vraiment de différentes versions de la journalisation des communs? Le dernier devrait fonctionner correctement avec les deux, non? – Thilo

+2

Notez que les gens de commun-lang vont cette route. Commons Lang 3 utilisera le nom de package org.apache.commons.lang3. Si vous allez avoir des changements d'API incompatibles, un nouveau nom de paquet n'est probablement pas la pire idée. – Thilo