2010-02-01 11 views
37

no pude encontrar una respuesta clara a esta pregunta en otro lugar, así que trataremos aquí:¿Cómo encontrar qué jarras y en qué orden las carga un cargador de clases?

¿Hay alguna manera (programática o de otro tipo) para obtener una lista de los frascos/clases cargadas por un cargador de clases de aplicaciones en el preciso orden que fueron cargados? Por Application Classloader me refiero al cargador de clases que carga una aplicación EAR en un servidor de aplicaciones (WLS, WAS, JBoss ...), pero obviamente se aplica a cualquier cargador de clases.

Por lo tanto, para generalizar, lo que me gustaría saber es la lista y el orden de los JAR cargados por un cargador de clases especificado. No clases individuales, eso es bastante fácil de averiguar llamando al classloader.getPackages(), pero una lista de archivos JAR cargados por este cargador de clases.

Respuesta

11

La respuesta corta es no. Los cargadores de clases no están obligados a exponer su lógica de búsqueda.

Sin embargo, si su instancia de classloader resulta ser URLClassLoader o una subclase, entonces tiene acceso a la lista de jarras/directorios, a través del método getURLs(). Según el documento para esta clase, esas URL se buscarán en orden.

En la práctica, si está tratando de averiguar de dónde se está cargando una clase, La respuesta de Steve es probablemente más útil.

+2

Gracias, kdgregory. Este es el enfoque que finalmente utilicé, básicamente escribí una utilidad que averigua la jerarquía del cargador de clases en el tiempo de ejecución y consulta cada cargador de clases qué lista de recursos han cargado usando el método getURLs() si está disponible. Funcionó bien para WLS y WAS. En el caso de WLS, sus propios cargadores de clases no extienden URLClassloader, pero sí tienen un método diferente, getClassPath(), que devuelve una lista ordenada de entradas de classpath. Y todos los cargadores de clases WAS parecen extender el cargador URLClass, así que getURLs() funcionó bien. Todavía no lo he probado en JBoss. Marina – Marina

58

Ha intentado utilizar la opción JVM -verbose:class. Muestra todos los archivos y clases JAR cargados.

Ejemplo:

[Opened C:\Program Files\JDK160~1\jre\lib\rt.jar] 
[Loaded java.lang.Object from C:\Program Files\JDK160~1\jre\lib\rt.jar] 
+0

Gracias, Steve - sí, probé esa opción y funciona bien si solo estás interesado en saber qué cargador de clases y de qué .jar cargó una clase específica. El resultado es demasiado abrumador, ya que nuestra aplicación tiene miles de clases :). He usado un enfoque similar al sugerido por kdgregory, ver abajo. – Marina

0

Pase por el dominio de protección de la clase (la combinación de ubicación/certificado). p.ej. PDFParser.class para obtener así ...

PDFParser.class.getProtectionDomain().getCodeSource().getLocation().toString() 

Si se carga de las clases JRE o desde directorios aprobados se lanzará una excepción cos estas clases de carga sin protección ...

0

Como una forma alternativa, puede usar este fragmento de código. El resultado es un archivo que consta de archivos jar relacionados con un cargador de clases y archivos de clase cargados por los cargadores de clase de un objeto (cadena de cargadores de clases, incluidos sus padres hasta el cargador de clases raíz). Los cargadores de clases están separados por estrellas.

Object obj = this; 
ClassLoader classLoader = obj.getClass().getClassLoader(); 
File file = new File("classlodersClassesJars.txt"); 
if(file.exists()) { 
    file.delete(); 
} 
if(classLoader != null) { // to escape from system classes that are loaded by bootstrap class-loader such as String. 
    do { 
     try { 
      Class clClass = classLoader.getClass(); 
      while(clClass != ClassLoader.class){ 
        clClass = clClass.getSuperclass(); 
      } 
      java.lang.reflect.Field domainField = clClass.getDeclaredField("domains"); 
      java.lang.reflect.Field classesField = clClass.getDeclaredField("classes"); 
      domainField.setAccessible(true); 
      classesField.setAccessible(true); 
      HashSet domains = (HashSet<String>) domainField.get(classLoader); 
      Vector classes = (Vector) classesField.get(classLoader); 
      FileOutputStream fos = new FileOutputStream("classlodersClassesJars.txt", true); 
      fos.write(("\n******************** " + classLoader.toString() + "\n").getBytes()); 
      fos.write(Arrays.toString(classes.toArray()).getBytes()); 
      Object[] reverseDomains = domains.toArray(); 
      org.apache.commons.lang.ArrayUtils.reverse(reverseDomains); 
      fos.write(Arrays.toString(reverseDomains).getBytes()); 
      fos.close(); 
      classLoader = classLoader.getParent(); 
     } catch (Exception exception) { 
      exception.printStackTrace(); 
      // TODO 
     } 
    } while (classLoader.getParent() != null); 
} 
Cuestiones relacionadas