2010-08-08 43 views
5

Estoy tratando de definir un ClassLoader personalizado.ContextClassLoader no se conecta

public class ExampleLoader extends ClassLoader 
{ 
    public Class<?> findClass(String name) throws ClassNotFoundException 
    { 
     System.out.println("This never gets printed"); 
     return super.findClass(name); 
    } 

    public Class<?> loadClass(String name, boolean b) 
     throws ClassNotFoundException 
    { 
     System.out.println("This never gets printed"); 
     return super.loadClass(name, b); 
    } 
} 

Y por supuesto mi código para probarlo:

public class Tester 
{ 
    public static void main(String[] args) 
    { 
     Thread t = new FooThread(); 
     t.setContextClassLoader(new ExampleLoader()); 
     t.start(); 
    } 
} 

class FooThread extends Thread 
{ 
    public void run() 
    { 
     new RandomClass(); 
    } 
} 

El problema es que mis líneas no se imprimen. Claramente me falta algo.

Respuesta

6

Esto se relaciona con bug 4868493. Aquí está un citan de relevancia:

Por desgracia, la documentación para getContextClassLoader y setContextClassLoader podría llevar a la conclusión de que el código de del solicitante debería funcionar como se espera.

Sin embargo, hay una regla básica en la carga de clases - no clase puede nunca cargar automáticamente una clase que es "aguas abajo", es decir, que no puede ser cargado directamente por esa clase ClassLoader o uno de su antepasado ClassLoaders.

Esto se describe en varios lugares. Por ejemplo, medite en el libro blanco disponible aquí: http://www.javageeks.com/Papers/ClassForName/index.html para obtener la iluminación.

El punto clave parece ser que el cargador de clase de contexto no se usa automáticamente por el lenguaje Java. Es solo un lugar convencional para almacenar el cargador de clases de contexto para que otras clases puedan usarlo con el 3-argument form of Class.forName.

La especificación para Thread.getContextClassLoader y Thread.setContextClassLoader debe aclararse, y el significado de "cargador de clases de contexto" debe aclararse . Re-clasificando como un error de doc.

La especificación no ha sido aclarada aún.

Para conseguir que funcione lo que en un inicio se desea, sustituir new RandomClass() por

Class.forName(RandomClass.class.getName(), 
       true, 
       getContextClassLoader()).newInstance(); 

Esta impresora, contradictoriamente, lo siguiente:

This never gets printed
+0

Por curiosidad, ¿cómo aplicaciones como Tomcat hacer este trabajo? Según tengo entendido, todas las tomas webapps de tomcat se ejecutan desde un jvm compartido, pero cuando usan clases, las definiciones de clase provienen de sus respectivas guerras. ¿Alguna idea de cómo logran esto? – Jim

+2

Usan 'ClassLoader # loadClass()'. La instancia de 'ClassLoader' se almacena y pasa en el hilo de esta manera. Un buen punto de partida para buscar en el código fuente es 'org.apache.catalina.core.DefaultInstanceManager'. – BalusC

0

Normalmente, todos los cargadores de clases en una JVM se organizan en una jerarquía de modo que cada cargador de clases (excepto el cargador de clases primordial que inicia la JVM completa) tenga un padre único. Cuando se le pide que cargue una clase, se espera que cada cargador de clases compatible delegue la carga en su padre primero e intente definir la clase solo si el padre falla.

Lo mismo está ocurriendo en su caso. Se debe cargar "RandomClass", ContextClassLoader delega a su elemento primario y así sucesivamente. Y uno de los cargadores de clase padre fue capaz de cargar "RandomClass" (RandomClass estaba en classpath de parent). Por esta razón, su SOP no aparece.

referencia siguiente artículo poco viejo pero bueno:

http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html?page=1

Cuestiones relacionadas