Java – Récupère une liste de toutes les classes chargées dans la JVM

Je voudrais obtenir une liste de toutes les classes appartenant à un certain paquet ainsi que tous leurs enfants. Les classes peuvent ou non être déjà chargées dans la JVM.

Ce n’est pas une solution programmatique mais vous pouvez courir

java -verbose:class .... 

et la JVM videra ce qu’elle charge et d’où.

 [Opened /usr/java/j2sdk1.4.1/jre/lib/rt.jar] [Opened /usr/java/j2sdk1.4.1/jre/lib/sunrsasign.jar] [Opened /usr/java/j2sdk1.4.1/jre/lib/jsse.jar] [Opened /usr/java/j2sdk1.4.1/jre/lib/jce.jar] [Opened /usr/java/j2sdk1.4.1/jre/lib/charsets.jar] [Loaded java.lang.Object from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] [Loaded java.io.Serializable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] [Loaded java.lang.Comparable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] [Loaded java.lang.CharSequence from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] [Loaded java.lang.Ssortingng from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] 

Voir ici pour plus de détails.

en utilisant la bibliothèque Reflections , c’est facile comme:

 Reflections reflections = new Reflections("my.pkg", new SubTypesScanner(false)); 

Cela permettrait d’parsingr toutes les classes dans l’URL / s qui contient le package my.pkg.

  • le paramètre false signifie – n’excluez pas la classe Object, qui est exclue par défaut.
  • Dans certains scénarios (différents conteneurs), vous pouvez passer le classLoader ainsi qu’un paramètre.

Ainsi, obtenir toutes les classes récupère efficacement tous les sous-types d’Object, de manière transitoire:

 Set allClasses = reflections.getStore().getSubTypesOf(Object.class.getName()); 

(La manière habituelle de reflections.getSubTypesOf(Object.class) provoquerait le chargement de toutes les classes dans PermGen et lancerait probablement OutOfMemoryError. Vous ne voulez pas le faire …)

Si vous voulez obtenir tous les sous-types directs d’Object (ou de tout autre type), sans obtenir tous ses sous-types transitifs, utilisez ceci:

 Collection directSubtypes = reflections.getStore().get(SubTypesScanner.class).get(Object.class.getName()); 

Il y a plusieurs réponses à cette question, en partie à cause d’une question ambiguë – le titre parle de classes chargées par la JVM, alors que le contenu de la question dit “peut ou non être chargé par la JVM”.

En supposant que l’OP a besoin de classes chargées par la JVM par un chargeur de classes donné et que ces classes – mon besoin aussi – il existe une solution ( élaborée ici ) qui se présente comme suit:

 import java.net.URL; import java.util.Enumeration; import java.util.Iterator; import java.util.Vector; public class CPTest { private static Iterator list(ClassLoader CL) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { Class CL_class = CL.getClass(); while (CL_class != java.lang.ClassLoader.class) { CL_class = CL_class.getSuperclass(); } java.lang.reflect.Field ClassLoader_classes_field = CL_class .getDeclaredField("classes"); ClassLoader_classes_field.setAccessible(true); Vector classes = (Vector) ClassLoader_classes_field.get(CL); return classes.iterator(); } public static void main(Ssortingng args[]) throws Exception { ClassLoader myCL = Thread.currentThread().getContextClassLoader(); while (myCL != null) { System.out.println("ClassLoader: " + myCL); for (Iterator iter = list(myCL); iter.hasNext();) { System.out.println("\t" + iter.next()); } myCL = myCL.getParent(); } } } 

Une des choses intéressantes à ce sujet est que vous pouvez choisir un chargeur de classes arbitraire à vérifier. Il est cependant susceptible de se casser si des composants internes de classe classer le chargeur devaient être changés, de sorte qu’il doit être utilisé comme outil de diagnostic unique.

Une approche alternative à celles décrites ci-dessus consisterait à créer un agent externe à l’aide de java.lang.instrument pour savoir quelles classes sont chargées et exécuter votre programme avec le commutateur -javaagent :

 import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.security.ProtectionDomain; public class SimpleTransformer implements ClassFileTransformer { public SimpleTransformer() { super(); } public byte[] transform(ClassLoader loader, Ssortingng className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException { System.out.println("Loading class: " + className); return bytes; } } 

Cette approche présente l’avantage supplémentaire de vous fournir des informations sur le ClassLoader chargé dans une classe donnée.

Je vous suggère également d’écrire un agent -javagent , mais d’utiliser la méthode getAllLoadedClasses au lieu de transformer des classes.

Pour synchroniser avec votre code client (code Java normal), créez un socket et communiquez avec l’agent via celui-ci. Ensuite, vous pouvez déclencher une méthode “list all classes” chaque fois que vous en avez besoin.

Un moyen si vous connaissez déjà le chemin du niveau supérieur du paquet est d’utiliser OpenPojo

 final List pojoClasses = PojoClassFactory.getPojoClassesRecursively("my.package.path", null); 

Ensuite, vous pouvez passer en revue la liste et effectuer toutes les fonctionnalités souhaitées.

Vous pourriez être en mesure d’obtenir une liste des classes chargées via le chargeur de classe, mais cela n’inclurait pas les classes que vous n’avez pas encore chargées, mais qui se trouvent sur votre chemin de classe.

Pour obtenir toutes les classes sur votre chemin de classe, vous devez faire quelque chose comme votre deuxième solution. Si vous voulez vraiment des classes qui sont actuellement “chargées” (en d’autres termes, des classes que vous avez déjà référencées, auxquelles vous avez accédé ou instancié), vous devez affiner votre question pour l’indiquer.

Exécutez votre code sous une JVM JRockit, puis utilisez JRCMD print_class_summary

Ceci affichera toutes les classes chargées, une sur chaque ligne.

Eh bien, ce que j’ai fait était simplement de lister tous les fichiers dans le classpath. Ce n’est peut-être pas une solution glorieuse, mais cela fonctionne de manière fiable et me donne tout ce que je veux, et plus encore.

Ce programme imprime toutes les classes avec son chemin physique. use peut simplement copier ceci dans n’importe quel JSP si vous devez parsingr le chargement de la classe depuis n’importe quel serveur web / application.

 import java.lang.reflect.Field; import java.util.Vector; public class TestMain { public static void main(Ssortingng[] args) { Field f; try { f = ClassLoader.class.getDeclaredField("classes"); f.setAccessible(true); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Vector classes = (Vector) f.get(classLoader); for(Class cls : classes){ java.net.URL location = cls.getResource('/' + cls.getName().replace('.', '/') + ".class"); System.out.println("

"+location +"

"); } } catch (Exception e) { e.printStackTrace(); } } }