2010-11-04 14 views
25

¡Hola a todos y gracias por la atención! Tengo un problema que debe ser fácil y obvio, pero estoy atascado.¿Cómo poner Custom ClassLoader para usar?

Deseo entregar clases de Java creadas dinámicamente para ser utilizadas por una biblioteca de terceros a través de un ClassLoader personalizado.

Ahora mi problema es: ¿cómo puedo configurar mi ClassLoader personalizado para cargar estas clases cuando no las cargo directamente?

Pensé que cuando usaba mi ClassLoader para cargar cierta clase, se convertía en el ClassLoader de esta clase, y todas las clases cargadas de esa clase se canalizarían a través de mi ClassLoader.

Creé un ClassLoader personalizado, siguiendo este tutorial oficial: http://java.sun.com/developer/onlineTraining/Security/Fundamentals/magercises/ClassLoader/help.html.

public class DynamicClassloader extends ClassLoader { 

    private Map<String, Class<?>> classesMap = new HashMap<String, Class<?>>(); 

    public DynamicClassloader(ClassLoader parent) { 
     // Also tried super(parent); 
     super(sun.misc.Launcher.getLauncher().getClassLoader()); 
    } 

    // Adding dynamically created classes 
    public void defineClass(String name, Class<?> clazz) { 
     classesMap.put(name, clazz); 
    } 

    @Override 
    protected Class<?> findClass(String name) throws ClassNotFoundException { 
     // load from parent 
     Class<?> result = findLoadedClass(name); 
     if (result != null) { 
      return result; 
     } 
     try { 
      result = findSystemClass(name); 
     } catch (Exception e) { 
      // Ignore these 
     } 
     if (result != null) { 
      return result; 
     } 
     result = classesMap.get(name); 
     if (result == null) { 
      throw new ClassNotFoundException(name); 
     } 
     return result; 
    } 
} 

que quería utilizar esto en otro lugar en el código de esa manera:

ClassLoader thisClassLoader = this.getClass().getClassLoader(); 
((DynamicClassloader) thisClassLoader).defineClass(className, dynClass); 

Ahora mi problema es que cuando llamo findSystemClass(name) de la tercera clase de biblioteca de partido, el cargador de clases padre encuentra esta clase (porque está en la ruta de clases) y se convierte en su ClassLoader. Y dado que el ClassLoader padre no sabe acerca de mi ClassLoader personalizado, está efectivamente fuera de uso y this.getClass().getClassLoader() no se puede convertir a DynamicClassLoader.

Otro enfoque sería configurar mi ClassLoader para que sea el sistema ClassLoader a través del argumento de JVM -Djava.system.class.loader=my.DynamicClassloader. Pero eso me da un StackOverflowError:

... 
at de.unisaarland.cs.st.DynamicClassloader.findClass(DynamicClassloader.java:39) 
at java.lang.ClassLoader.loadClass(ClassLoader.java:307) 
at java.lang.ClassLoader.loadClass(ClassLoader.java:248) 
at java.lang.ClassLoader.findSystemClass(ClassLoader.java:916) 
at de.unisaarland.cs.st.DynamicClassloader.findClass(DynamicClassloader.java:39) 
    ... 

Esto debe ser muy fácil de hacer, pero ahora estoy sin ideas ... cualquier ayuda es muy apreciada!

+0

relacionada a http://stackoverflow.com/questions/6366288/how-to-change-default-class-loader-in-java, http://stackoverflow.com/questions/5380275/replacement-system-classloader-for-classes-in-jars-containing-jars/19128964 # 191 28964 y http: // stackoverflow.com/questions/5380275/replacement-system-classloader-for-classes-in-jar-containing-jar. – roesslerj

Respuesta

19

No estoy seguro. Entiendo la pregunta, usted tiene una lib de terceros y desea que use su cargador de clases para cargar clases.

Si tiene suerte el tercer partido lib utiliza el cargador de clases contexto hilos que se pueden establecer utilizando Thread.currentThread().setContextClassLoader(myClassLoader), en el mismo hilo se puede acceder a este cargador de clases con Thread.currentThread().getContextClassLoader() ...

Otro punto, pero no estoy seguro que es importante en su contexto, es que también se puede escribir un cargador de clases de padres y última que intentará cargar la clase antes de delegar a su padre (en vez de intentar delegar primero)

editar después de su comentario:

parent_last classloader marcará la diferencia si su biblioteca no se basa en el cargador de clases de contexto de subprocesos, entonces tiene que cargar la biblioteca con su último cargador de clases, configurando su cargador de clases como el cargador de clases para la biblioteca en lugar de su cargador padre (el padre de su cargador de clases) ...

Usted también puede hacer un cargador de clases con un comportamiento de padres y primera, pero para su biblioteca tercera parte ...

And a good link about classloaders...

+0

El ContextClassLoader es una buena idea, lo intentaré. ¡Muchas gracias! En cuanto al padre y el último cargador de clases: no creo que esto haga la diferencia. De hecho, no quiero definir la clase que estoy cargando, solo quiero que mi ClassLoader sea el ClassLoader actual, de modo que todas las llamadas posteriores a 'findClass' se canalicen a través de él ... – roesslerj

+0

¿Cómo se escribe una clase para padres? ¿cargador? ¿no hay una implementación existente? si no, entonces o no es un problema común o hay otra forma mejor de resolverlo. –

+0

El enlace está muerto – grimmeld