2010-04-21 3 views

Répondre

27

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

Selon les docs:

Renvoie un tableau de toutes les classes pour lesquelles chargeur est un chargeur d'amorçage.

Je ne suis pas sûr de ce que signifie "initiateur loader". 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 le JAR agent (qui est séparé de l'application JAR) peut obtenir une instance de l'interface Instrumentation. Un moyen simple de le rendre disponible à l'application est de créer un JAR d'agent contenant une classe avec une méthode premain qui ne fait rien d'autre qu'une sauvegarde de l'instance Instrumentation dans les propriétés du système.

Exemple 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 manifeste:

Manifest-Version: 1.0 
Premain-Class: InstrumentHook 

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

Exemple d'application classe

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

Mais comment obtenir une instance d'instrumentation? –

+1

@Arne Burmeister, voir la description du paquet: http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.html – finnw

+0

donc si je comprends bien, je dois écrire un agent, qui contient une méthode signée "public static void premain" (String agentArgs, Instrumentation inst); " puis invoquer les méthodes Instrumentation via l'inst ref? – Yaneeve

46

Essayez ceci. C'est une solution hackerish mais ça ira.

Le champ classes dans n'importe quel chargeur de classe (sous l'implémentation de Sun depuis la version 1.0) contient des références aux classes définies par le chargeur afin qu'elles ne soient pas GC'd. Vous pouvez tirer un bénéfice de la réflexion.

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

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

Sur Android, j'obtiens 'Aucune classe de champ dans class Ljava/lang/ClassLoader' –

+0

@NathanH, techniquement, Android n'est même pas Java (jusqu'à ce qu'il soit OpenJDK), mais comme je l'ai mentionné, c'est une solution hackerish qui repose sur la façon dont classloader a été implémenté depuis plus de 17 ans. Il n'y a aucune garantie que le hack proposé fonctionnerait à l'avenir non plus. Aussi sur Android je ne peux pas vraiment voir le code de middleware de fonctionnement (avec la charge de classe dynamique), donc il ne devrait pas être nécessaire d'obtenir les classes chargées. – bestsss

+0

Android peut faire une gestion de classe dynamique, je le fais tout le temps avec [JavaX] (http://javax.ai1.lol). En fait, je charge tous mes programmes principaux de cette façon (l'application est juste un bout). –

Questions connexes