Java ServiceLoader avec plusieurs chargeurs de classes
Quelles sont les meilleures pratiques pour l'utilisation de ServiceLoader dans un Environnement avec plusieurs chargeurs de classes? La documentation recommande de créer et d'enregistrer une seule instance du service au moment de l'initialisation:
private static ServiceLoader<CodecSet> codecSetLoader = ServiceLoader.load(CodecSet.class);
Ce serait initialiser le ServiceLoader en utilisant le contexte actuel du chargeur de classe. Supposons maintenant que cet extrait est contenue dans une classe chargée partagé un chargeur de classe dans un conteneur web et plusieurs applications web souhaitez définir leurs propres implémentations de service. Ce ne serait pas obtenir ramassé dans le code ci-dessus, il pourrait même être possible que le chargeur est initialisé à l'aide de la première webapps contexte du chargeur de classe et de fournir la mauvaise mise en œuvre à d'autres utilisateurs.
Toujours la création d'une nouvelle ServiceLoader semble un gaspillage de performance sage, car il a d'énumérer et d'analyser les fichiers de service à chaque fois. Edit: Cela peut même être un gros problème de performance comme indiqué dans cette réponse au sujet de java XPath mise en œuvre.
Comment d'autres bibliothèques de gérer cela? Ils ne le cache de la mise en œuvre par des chargeurs de classes, font-ils d'analyse de leur configuration, à chaque fois, ou ont-ils simplement ignorer ce problème et ne fonctionne que pour un chargeur de classe?
- salut Horstmann Look de ce vous.stackoverflow.com/questions/1959991/...
- Jetez un oeil à Apache Camel - il traite ce problème avec élégance, à la fois dans les applications JEE et OSGi (remarque il y a également un module de chargement de classes jboss dans le Chameau extras paquet hébergés sur googlecode)
- pouvez-vous m'indiquer un peu plus de détails sur la manière dont Apache Camel permet de résoudre ce problème?
- il n'y a pas beaucoup de documentation sur (comme ne faisant pas partie de l'API publique), à l'exception de camel.apache.org/pluggable-class-resolvers.html jetez un oeil à org.apache.à dos de chameau.le spi.ClassResolver et il est sous-classes (plusieurs chameau-core (par exemple, OSGi),voir chameau extras de projet code.google.com/a/apache-extras.org/p/camel-extra/source/browse/... ). Sinon JBossOSGi prétend être la poignée ServiceLoader jbossosgi.blogspot.com/2010/01/...
Vous devez vous connecter pour publier un commentaire.
Personnellement, je n'aime pas le
ServiceLoader
en toutes circonstances. C'est lent et inutilement coûteux et il ya peu que vous pouvez faire pour l'optimiser.Je trouve aussi que c'est un peu limité -- vous avez vraiment besoin de sortir de votre chemin si vous voulez faire plus de recherche par type seul.
xbean-finder ResourceFinder
Avant notre attention trop court, voici comment il est possible de remplacer une ServiceLoader
Cela permettra de trouver tous les
META-INF/services/org.acme.Plugin
implémentations dans votre classpath.Remarque il ne fait pas instancier toutes les instances. De choisir celle(s) que vous voulez et vous êtes l'un
newInstance()
appel loin de disposer d'une instance.Pourquoi est-ce agréable?
newInstance()
avec une bonne gestion des exceptions? Pas dur.Rétrécissement de la zone de recherche
Si vous voulez juste vérifier les URLs, vous pouvez le faire facilement:
Ici, seuls les "some.jar' objet d'une recherche sur tout l'utilisation de ce ResourceFinder instance.
Il y a aussi une classe utilitaire appelé
UrlSet
ce qui peut rendre la sélection des Url depuis le classpath très facile.Autre "service" styles
Dit que vous vouliez appliquer la
ServiceLoader
type de concept à la refonte de gestion des URL et de trouver ou charger lejava.net.URLStreamHandler
pour un protocole spécifique.Voici comment vous pourriez disposition de les services dans votre classpath:
META-INF/java.net.URLStreamHandler/foo
META-INF/java.net.URLStreamHandler/bar
META-INF/java.net.URLStreamHandler/baz
Où
foo
est un fichier texte qui contient le nom de la mise en œuvre des services tout comme avant. Maintenant, dire que quelqu'un crée unfoo://...
URL. Nous pouvons trouver de la mise en œuvre pour que rapidement, via:Autre "service" styles 2
Dit que vous vouliez mettre certaines informations de configuration dans votre fichier de service, de sorte qu'il contient plus que juste un nom de classe. Voici un autre style qui résout services à des fichiers de propriétés. Par convention, l'une des clés serait les noms de classe et les autres touches serait injectable propriétés.
Donc ici
red
est un fichier de propriétésMETA-INF/org.acme.Plugin/red
META-INF/org.acme.Plugin/blue
META-INF/org.acme.Plugin/green
Vous pouvez regarder les choses de la même façon qu'avant.
Voici comment vous pouvez utiliser ces propriétés avec
xbean-reflect
, une autre petite bibliothèque qui peut vous donner cadre-gratuit Cio. Vous donnez simplement le nom de la classe et quelques paires nom /valeur, et il permettra de construire et de les injecter.Voici à quoi cela peut ressembler "orthographié" en forme longue:
La
xbean-reflect
bibliothèque est une étape au-delà de l'intégré dans JavaBeans API, mais un peu mieux, sans vous obliger à aller tout le chemin vers un plein sur Cio cadre comme Guice ou au Printemps. Il prend en charge l'usine de méthodes et constructeur args et setter/champ d'injection.Pourquoi le ServiceLoader si limitée?
Obsolète code dans la JVM des dommages-intérêts le langage Java lui-même. Beaucoup de choses sont taillées pour l'os avant d'être ajoutés à la JVM, parce que vous ne pouvez pas ajuster par la suite. Le
ServiceLoader
est un excellent exemple de cela. L'API est limitée et OpenJDK mise en œuvre est quelque part autour de 500 lignes, y compris javadoc.Il n'y a rien de compliqué, il y et son remplacement est facile. Si cela ne fonctionne pas pour vous, ne l'utilisez pas.
Classpath portée
Api de côté, dans la pure pratique de limiter le champ de l'Url de recherche est la vraie solution à ce problème. App les Serveurs ont beaucoup d'Url par eux-mêmes, pas y compris les bocaux dans votre application. Tomcat 7 sur OSX, par exemple, a environ 40~ Url du StandardClassLoader seul (ce qui est le parent de tous les webapp chargeurs de classes).
Le plus grand de votre serveur d'application le plus à même une simple recherche prendra.
La mise en cache n'aide pas si vous l'intention de chercher plus d'une entrée. Ainsi, il peut ajouter un peu de mal fuites. Peut être un réel perdre-perdre du scénario.
Étroite de l'Url vers le 5 ou 12 qui compte vraiment pour vous et vous pouvez faire toutes sortes de services de chargement et de ne jamais l'avis de la frapper.
Avez-vous essayé d'utiliser les deux argument version de sorte que vous pouvez spécifier le chargeur de classe à utiliser? C'est à dire,
java.util.ServiceLoader.load(Class, ClassLoader)
Mu.
Dans un 1x WebContainer <-> Nx WebApplication système, le ServiceLoader instancié dans le WebContainer ne sera pas ramasser toutes les classes définies dans les Applications, seulement ceux dans le conteneur. Un ServiceLoader instancié dans une WebApplication permettra de détecter les classes définies dans la demande à ceux définis dans le conteneur.
Gardez à l'esprit d'Applications devront être séparés, sont conçues de cette manière, les choses sera pause si vous essayez de contourner cela, et ils ne sont pas la méthode et système pour étendre le conteneur - si votre bibliothèque est un Pot simple, il suffit de déposer dans l'extension appropriée dossier du conteneur.
J'aime vraiment Neil réponse dans le lien que j'ai ajouté dans mon commentaire. En raison de j'ai la même experences dans mon dernier projet.
"Une autre chose à garder à l'esprit avec ServiceLoader est d'essayer de résumé le mécanisme de recherche. Le mécanisme de publication est très agréable et propre et déclarative. Mais la recherche (via java.util.ServiceLoader) est aussi laid que l'enfer, mis en œuvre comme un chemin de classe scanner qui rompt horriblement si vous placez le code dans n'importe quel environnement (comme OSGi ou Java EE) qui n'ont pas de visibilité à l'échelle mondiale. Si votre code est enchevêtrée avec cela, alors vous aurez du mal à le faire fonctionner sur OSGi plus tard. Mieux d'écrire une abstraction que l'on peut remplacer le moment venu."
J'ai rencontré ce problème dans OSGi environnement en fait c'est juste de l'éclipse dans notre projet. Mais heureusement, j'ai résolu en temps opportun. Ma solution est d'utiliser une classe à partir du plugin je veux charger ,et d'obtenir des chargeurs de classes à partir d'elle. Qui sera valide d'un correctif. Je n'ai pas utilisé la norme ServiceLoader, Mais mes processus est assez similaire, l'utilisation des propriétés pour définir les classes de plugin j'ai besoin de charger. Et je sais qu'il existe une autre façon de connaître chaque plugin du chargeur de classe. Mais au moins, je n'ai pas besoin de les utiliser.
Honnête, je n'aime pas les génériques utilisés dans ServiceLoader. Parce que c'limitée que l'on ServiceLoader ne peut gérer que des classes pour une interface. Bien est-il vraiment utile? Dans mon application, il ne vous force pas à cette restriction. Je viens d'utiliser une mise en œuvre de loader pour charger toutes les classes de plugin. Je ne vois pas la raison de l'utilisation de deux ou plus. En raison de la consommation peut savoir à partir des fichiers de configuration sur les relations entre les interfaces et la mise en œuvre.
Cette question semblent être plus compliqué que j'ai d'abord prévu. Comme je le vois
c', il existe 3 stratégies possibles pour faire face à ServiceLoaders.
Utilisation statique ServiceLoader instance et uniquement en charge le chargement de classes à partir de
le même chargeur de classe comme l'un tient le ServiceLoader de référence. Cette
serait de travailler quand
De la configuration du service et la mise en commun des chargeurs de classes
et tous les enfants les chargeurs de classe sont en utilisant le même de la mise en œuvre. L'exemple
dans la documentation est orientée vers theis cas d'utilisation.
Ou
De Configuration et de mise en œuvre sont mis dans chaque enfant du chargeur de classe et
déployée le long de chaque webapp dans
WEB-INF/lib
.Dans ce scénario, il n'est pas possible de déployer le service dans une commune du chargeur de classe
et de laisser chaque webapp choisir son propre service de mise en œuvre.
Initialiser le ServiceLoader à chaque accès, en passant le contexte du chargeur de classe de
le thread courant en tant que second paramètre. Cette approche est prise à la JAXP
et api JAXB, même s'ils utilisent leur propre FactoryFinder mise en œuvre
au lieu de ServiceLoader. Il est ainsi possible de regrouper un analyseur xml avec une webapp
et qu'automatiquement obtenir ramassé par exemple par
DocumentBuilderFactory#newInstance
.Cette recherche a un l'impact sur les performances, mais dans le cas de l'analyse xml
le temps de regarder jusqu'à la mise en œuvre est faible par rapport au temps nécessaire pour
en fait analyser un document xml. Dans la bibliothèque, je suis prévoyant l'usine
lui-même est assez simple pour la recherche de temps de dominer le rendement.
En quelque sorte de cache de la mise en œuvre de la classe avec le contexte du chargeur de classe comme la clé.
Je ne suis pas entièrement sûr si cela est possible dans tous les cas ci-dessus sans
causer des fuites de mémoire.
En conclusion, je vais probablement être en ignorant ce problème et exiger que la bibliothèque
est déployé à l'intérieur de chaque webapp, c'est à dire l'option 1b ci-dessus.