2009-06-03 13 views
30

Existe-t-il un moyen de déterminer quelles classes sont chargées à partir de quels jarres lors de l'exécution?Comment explorer les classes chargées à partir des fichiers JAR?

Je suis sûr que nous avons tous été en JAR enfer avant. J'ai traversé ce problème beaucoup de dépannage ClassNotFoundException s et NoClassDefFoundError sur des projets. Je voudrais éviter de trouver toutes les instances d'une classe dans les pots et d'utiliser le processus d'élimination sur le code provoquant un CNFE pour trouver le coupable. Est-ce que des outils de profilage ou de gestion vous donneront ce genre d'information?

Ce problème est super ennuyeux uniquement parce que nous devrions avoir cette information au moment où la classe est chargée. Il doit y avoir un moyen d'y arriver, ou de l'enregistrer et de le trouver, mais je ne connais rien qui puisse le faire, n'est-ce pas? Je sais que OSGi et les bundles/modules versionnés visent à faire de ce problème un problème ... mais cela ne semble pas vouloir disparaître de sitôt. :)

NOTE: J'ai trouvé cette question est un sous-ensemble de ma question liée aux classes chargées à partir de pots versionnés.

Mise à jour: Un peu lié, cet article explique une stratégie pour rechercher une classe dans les fichiers jar (soit sous le répertoire courant) ou dans votre M2_REPO. JarScan, scan all JAR files in all subfolders for specific class

Mise à jour 2: aussi un peu lié, JBoss Tattletale

+0

Jason Day a raison, ce fait un double d'une question que je posais pas si longtemps. http://stackoverflow.com/questions/779650/where-on-the-file-system-was-my-java-class-loaded-from – shsteimer

Répondre

56

En passant le commutateur -verbose:class à la commande java imprime chaque classe chargée et où il a été chargé.

Joops est aussi un bon outil pour trouver des classes manquantes à l'avance.

+2

Je viens d'essayer -verbose: option de classe. Est génial!!! Vraiment très utile – OscarRyz

+0

Nice - Joops a l'air cool - savez-vous s'il est assez intelligent pour suivre une classe référencée par Class.forName? – cwash

+0

Je serais surpris s'il pouvait suivre les références Class.forName, mais je ne sais pas avec certitude. Joops a également une commande 'which', vous pouvez donc l'utiliser pour vérifier manuellement les classes par leur nom. –

14

De code, vous pouvez appeler:

myObject.getClass().getProtectionDomain().getCodeSource() 

(Note, getProtectionDomain peut malheureusement revenir null (mauvaise conception), de sorte que "le bon code" vérifieriez pour cela.)

+0

Cela n'aiderait pas avec un CNFE ou NCDFE; quand l'as-tu fait? – cwash

+0

Vraisemblablement, si vous obtenez une exception ClassNotFoundException, vous savez sans doute déjà que la classe n'est dans aucun des pots. (En supposant que vous ne jouez pas avec des chargeurs de classe.) Il peut y avoir des problèmes s'il y a d'autres erreurs pendant le chargement de la classe, comme une superclasse manquante. –

+0

@ TomHawtin-tackline vous pouvez obtenir 'ClassNotFoundException' si un initialiseur statique de la classe renvoie une exception. Ensuite, vous avez la classe dans le fichier jar, mais le ClassLoader ne peut pas le charger. – hidralisk

4

Il y a un MBean pour le drapeau de la JVM mentionné par Jason Day ci-dessus.

Si vous utilisez JBoss, vous pouvez le faire à la demande en utilisant JMX, si vous ajoutez le serveur natif JMX MBean à votre config. Ajouter les années -D suivantes:

-Dcom.sun.management.jmxremote.port=3333 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false 
-Djboss.platform.mbeanserver 
-Djavax.management.builder.initial=org.jboss.system.server.jmx.MBeanServerBuilderImpl 
-DJBOSS_CLASSPATH="../lib/jboss-system-jmx.jar" 

Et vous pouvez voir ce paramètre sous la java.lang: classloading MBean et peut couper/désactiver à la volée. Ceci est utile si vous ne le souhaitez que pendant l'exécution d'un certain code.

Il existe également un MBean qui vous permet d'entrer un nom de classe complet et de voir d'où il provient à partir de la hiérarchie de classe. Le MBean s'appelle LoaderRepository et vous devrez appeler l'opération displayClassInfo() en passant le FQCN.

0

Dans WebSphere (WAS), vous pouvez utiliser une fonctionnalité appelée "classe Loader Viewer"

Activer la visionneuse de chargeur de classe premier en cliquant sur Serveurs> Types de serveur> Serveurs d'applications WebSphere> nom_serveur> Service de visionneuse de chargeur de classe, activez la service et redémarrez le serveur. Ensuite, vous pouvez aller à Dépannage> Class Loader Viewer et rechercher votre nom de classe ou de paquet.

https://www-01.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.nd.doc/ae/ttrb_classload_viewer.html?lang=en

0

Vous pouvez facilement exporter une opération de JMX pour accéder aux informations de package pour une classe chargée en vous traitez comme:

public static final class Jmx { 

    @JmxExport 
    public static Reflections.PackageInfo getPackageInfo(@JmxExport("className") final String className) { 
     return Reflections.getPackageInfo(className); 
    } 
    } 

et voici un simple test de l'unité d'exporter et invoquer:

@Test 
    public void testClassLocator() throws IOException, InstanceNotFoundException, MBeanException, ReflectionException { 
    Registry.export(Jmx.class); 
    Reflections.PackageInfo info = (Reflections.PackageInfo) Client.callOperation(
      "service:jmx:rmi:///jndi/rmi://:9999/jmxrmi", 
      Jmx.class.getPackage().getName(), 
      Jmx.class.getSimpleName(), "getPackageInfo", Registry.class.getName()); 
    System.out.println(info); 
    Assert.assertNotNull(info); 
    } 

cela est basé en utilisant une petite bibliothèque d'utilitaires de spf4j (http://www.spf4j.org)

vous pouvez voir ce code at et le test at