web-dev-qa-db-fra.com

Comment lister toutes les classes chargées dans un chargeur de classe spécifique

Pour des raisons de débogage et par curiosité, je souhaite répertorier toutes les classes chargées dans un chargeur de classe spécifique.

Étant donné que la plupart des méthodes d'un chargeur de classe sont protégées, quelle est la meilleure façon d'accomplir ce que je veux?

Merci!

39
Yaneeve

Instrumentation.getInitiatedClasses(ClassLoader) peut faire ce que vous voulez.

Selon les documents:

Renvoie un tableau de toutes les classes pour lesquelles le chargeur est un chargeur initiateur.

Je ne sais pas ce que signifie "lancer le chargeur". Si cela ne donne pas le bon résultat, essayez d'utiliser la méthode getAllLoadedClasses() et de filtrer manuellement par ClassLoader.


Comment obtenir une instance de Instrumentation

Seul l'agent JAR (qui est distinct du JAR d'application) peut obtenir une instance de l'interface Instrumentation. Un moyen simple de le rendre disponible pour l'application consiste à créer un JAR d'agent contenant une classe avec une méthode premain qui ne fait que sauvegarder une référence à l'instance Instrumentation dans les propriétés système.

Exemple de classe d'agent:

public class InstrumentHook {

    public static void premain(String agentArgs, Instrumentation inst) {
        if (agentArgs != null) {
            System.getProperties().put(AGENT_ARGS_KEY, agentArgs);
        }
        System.getProperties().put(INSTRUMENTATION_KEY, inst);
    }

    public static Instrumentation getInstrumentation() {
        return (Instrumentation) System.getProperties().get(INSTRUMENTATION_KEY);
    }

    // Needn't be a UUID - can be a String or any other object that
    // implements equals().    
    private static final Object AGENT_ARGS_KEY =
        UUID.fromString("887b43f3-c742-4b87-978d-70d2db74e40e");

    private static final Object INSTRUMENTATION_KEY =
        UUID.fromString("214ac54a-60a5-417e-b3b8-772e80a16667");

}

Exemple de manifeste:

Manifest-Version: 1.0
Premain-Class: InstrumentHook

Le JAR résultant doit ensuite être référencé par l'application et spécifiés sur la ligne de commande (avec le -javaagent option) lors du lancement de l'application. Il peut être chargé deux fois dans différents ClassLoader, mais ce n'est pas un problème car le système Properties est un singleton par processus.

Exemple de classe d'application

public class Main {
    public static void main(String[] args) {
        Instrumentation inst = InstrumentHook.getInstrumentation();
        for (Class<?> clazz: inst.getAllLoadedClasses()) {
            System.err.println(clazz.getName());
        }
    }
}
32
finnw

Essaye ça. C'est une solution de piratage informatique, mais elle fera l'affaire.

Le champ classes dans n'importe quel chargeur de classe (sous l'implémentation de Sun depuis 1.0) contient une référence dure aux classes définies par le chargeur afin qu'elles ne soient pas GC'd. Vous pouvez profiter de la réflexion via.

Field f = ClassLoader.class.getDeclaredField("classes");
f.setAccessible(true);

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Vector<Class> classes =  (Vector<Class>) f.get(classLoader);
56
bestsss