2012-04-17 12 views
5

tengo alguna clase A:Java ClassLoader cambio

public class A { 
    public A(String str) { 
     System.out.println("Create A instance: " + str); 
    } 

    public void methodA() { 
     System.out.println("#methodA1()"); 
    } 
} 

Y mi aplicación cargador de clases:

public class MyClassLoader extends ClassLoader { 
    public MyClassLoader() {  
     super(); 
    } 

    @Override 
    public synchronized Class<?> loadClass(String name) 
      throws ClassNotFoundException { 

     System.out.println("Load: " + name); 

     return super.loadClass(name); 
    } 
} 

Y ahora trato de cambiar el cargador de clases defecto en hilo actual:

import java.util.ArrayList; 
import java.util.List; 

public class ChangeLoaderTest { 
    public static void main(String[] args) { 
     // Save class loader so that we can restore later. 
     ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); 

     MyClassLoader newLoader = new MyClassLoader(); 
     try { 
      // Set new classloader. 
      Thread.currentThread().setContextClassLoader(newLoader); 

      // My class. 
      A a = new A("1"); 
      a.methodA(); 

      // Standard Java class. 
      List<Integer> list = new ArrayList<Integer>(); 
      list.add(2); 
      list.add(3); 
     } finally { 
      // Restore. 
      Thread.currentThread().setContextClassLoader(oldLoader); 
     } 
    } 
} 

Y ChangeLoaderTest salida:

Create A instance: 1 
#methodA1() 

Nadie

Load: ... 

¿Por qué? ¿Cómo puedo cambiar ClassLoader en algún hilo?

+0

* "Tengo alguna clase A:" * Ya estoy aburrido. No, eso no es estrictamente cierto, pero no voy a seguir leyendo. Mientras que algunas personas piensan que es mejor 'abstraer un problema' hasta el punto de poder expresarlo como símbolos obtusos, prefiero un contexto que ayude a explicar qué hay en la clase 'A' que hace que quieras cargarlo dinámicamente. ES DECIR. la clase 'A' podría ser una' UserDefinedPlugIn' - la última proporciona algún contexto, la primera no. –

+0

Ok, puedo explicar el contexto de esta pregunta. Tengo una clase que lee imágenes en 'BufferedImage'. A veces es 'ImageIO.read (archivo)', a veces es 'Sanselan.getBufferedImage (file)'.Tengo mi propia clase para guardar imágenes y debo crear 'BuffredImage' desde el archivo, luego copiar datos de' BufferedImage' a mi objeto. Quiero usar alguna clase proxy para capturar todos los métodos '#get (...)' para guardar información en mi objeto. – dzav

Respuesta

4

Como señala Marko Topolnik el context classloader is for use by frameworks. Para usar el cargador de clases usted mismo, debe llamar al loadClass("somepackage.A") y luego usar la API de reflexión para crear una nueva instancia de A (Class.newInstance()).

No podrá utilizar A ni sus métodos directamente en su fuente, ya que el código de llamada no conoce A: utiliza un cargador de clases diferente. Una interfaz o clase de base de A que puede cargar el cargador de clases normal se puede utilizar para evitar la reflexión.

interface AIF{ 
     void someMethod(); 
} 
class A implements AIF{ 
     public void someMethod(){} 
} 


public void test(){ 
    MyLoader loader = new MyLoader(); 
    Class cla = loader.loadClass("A"); 
    AIF a = (AIF) cla.newInstance(); 
    a.someMethod(); 

} 
+0

Desafortunadamente, no se puede definir un constructor no predeterminado en una interfaz (cualquier constructor para el caso) de la forma en que vanveber lo tiene. Por lo tanto, entre la reflexión ... – mazaneicha

+0

@mazaneicha, podría omitir eso creando una clase de fábrica y una interfaz de fábrica (solo si realmente odia la reflexión). – josefx

0

Creo que lo que sucede es que el cargador de clases de su aplicación que también es el "padre" de su cargador de clases puede ubicar A y cargarlo. Como resultado, su cargador de clases no se buscará ni se utilizará para cargar A.

Para ser honesto, no tengo mucha experiencia con cargadores de clases pero si subclases uno que utiliza una URL para la ruta de la clase (para que pueda localizar el archivo de clase) y el cargador de clases principal no puede cargarlo (no forma parte del classpath), se usará el personalizado.

3

Mecanismos contextClassLoader es no utilizado por las operaciones Java básicas como new. Solo está allí, por lo que varios frameworks pueden acceder al cargador de clases de contexto a cargo y cargar recursos, clases, etc. Java siempre usará el cargador de clases que cargó el código que se está ejecutando. Es a la que accede a través del ChangeLoaderTest.class.getClassLoader(), y no hay nada que pueda hacer al respecto.

0

El new A("1") no lo cortará. Usted tendrá que hacer algo como esto con el fin de cargar su clase en el contexto de un nuevo cargador de clases:

{ 
    Class classA = newLoader.loadClass("A"); 
    Constructor classAConstructor = myClass.getConstructor(String.class); 
    Method methodA = classA.getMethod("methodA",null); 
    Object objectA = classAConstructor.newInstance("A"); 
    Object result = methodA.invoke(objectA,null); 
} 

De lo contrario, como se mencionó anteriormente por user384706, el cargador de clases más "alto" se utiliza para localizar y cargar la clase A.

Cuestiones relacionadas