2009-06-03 6 views
30

¿Hay alguna forma de determinar qué clases se cargan desde qué jar en el tiempo de ejecución?¿Cómo explorar qué clases se cargan desde qué JAR?

Estoy seguro de que todos hemos estado en JAR hell antes. Me he encontrado con este problema con mucha resolución de problemas ClassNotFoundException sy NoClassDefFoundError s en proyectos. Me gustaría evitar encontrar todas las instancias de una clase en jarras y usar el proceso de eliminación en el código que hace que un CNFE encuentre al culpable.

¿Algún perfil o herramientas de administración le dará este tipo de información?

Este problema es súper molesto simplemente porque deberíamos tener esta información en el momento en que se carga la clase. Tiene que haber una manera de llegar a él, o grabarlo y encontrarlo, sin embargo, no sé nada de lo que hará esto, ¿verdad?

Sé que OSGi y los paquetes/módulos versionados apuntan a que esto no sea un problema ... pero parece que no va a desaparecer en el corto plazo. :)

NOTA: Encontré este question es un subconjunto de mi pregunta relacionada con las clases cargadas desde los archivos versionados.

Actualización: Algo relacionado, esta publicación explica una estrategia para buscar una clase dentro de jar (ya sea bajo el directorio actual) o en su M2_REPO. JarScan, scan all JAR files in all subfolders for specific class

Actualización 2: También de alguna manera relacionado, JBoss Tattletale

+0

Jason Day está en lo cierto, esto básicamente un duplicado de una pregunta que no pidió hace mucho tiempo. http://stackoverflow.com/questions/779650/where-on-the-file-system-was-my-java-class-loaded-from – shsteimer

Respuesta

56

Al pasar el interruptor -verbose:class al comando java imprimirá cada clase cargada y donde fue cargado desde.

Joops es también una buena herramienta para encontrar las clases que faltan con anticipación.

+2

Acabo de probar -verbose: class option. ¡¡¡Es increíble!!! Realmente muy útil – OscarRyz

+0

Bonito - Joops se ve bien - ¿sabes si es lo suficientemente inteligente como para seguir una clase a la que se hace referencia a través de Class.forName? – cwash

+0

Me sorprendería si pudiera seguir las referencias Class.forName, pero no estoy seguro. Joops también tiene un comando 'which', por lo que podría usarlo para verificar manualmente las clases por nombre. –

14

De código puede llamar:

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

(Nota, getProtectionDomain puede por desgracia volver null (mal diseño), por lo que "código apropiado" comprobaría para eso.)

+0

Esto no ayudaría con un CNFE o NCDFE; cuando has hecho esto? – cwash

+0

Presumiblemente, si obtienes una ClassNotFoundException, es probable que ya sepas que la clase no está en ninguna de las jarras. (Suponiendo que no está jugando con los cargadores de clases). Puede haber problemas si hay otros errores durante la carga de la clase, como una superclase faltante. –

+0

@ TomHawtin-tackline puede obtener 'ClassNotFoundException' si un inicializador estático de dicha clase arroja una excepción. Luego tiene la clase en el archivo jar, pero el ClassLoader no puede cargarlo. – hidralisk

4

Hay un MBean la bandera JVM mencionada por Jason Day arriba.

Si está utilizando JBoss, puede hacerlo a pedido usando JMX, si agrega el servidor JMX MBean nativo a su configuración. Agregue el siguiente -D de:

-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" 

Y luego se puede ver esta configuración bajo la java.lang: classloading MBean y se puede cortar encendido/apagado en la marcha. Esto es útil si solo lo quiere mientras ejecuta cierto código.

También hay un MBean que le permitirá ingresar un nombre de clase completamente calificado y ver de dónde se cargó en la jerarquía de clases. El MBean se llama LoaderRepository y querrá invocar la operación displayClassInfo(), pasando el FQCN.

0

En WebSphere (WAS) se puede utilizar una función denominada "Clase Visor Loader"

Habilitar el espectador cargador de clases primero haciendo clic en Servidores> Tipos de servidor> Servidores de aplicaciones WebSphere> nombre_servidor> Servicio de visor del cargador de clases, que el servicio y reiniciar el servidor.

Luego puede ir a Solución de problemas> Visor de cargador de clase y buscar el nombre de su clase o paquete.

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

0

Usted puede exportar una operación de JMX acceder a la información del paquete para cualquier clase cargada en procesar como:

public static final class Jmx { 

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

y aquí es una prueba de unidad sencilla para exportar e invocarlo:

@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); 
    } 

esto se basa el uso de algunos servicios públicos pequeña biblioteca de spf4j (http://www.spf4j.org)

se puede ver el código at y la prueba at

Cuestiones relacionadas