2010-11-04 21 views
25

Ciao a tutti e grazie per l'attenzione! Ho un problema che deve essere sia facile che ovvio, eppure sono bloccato.Come utilizzare ClassLoader personalizzato?

Desidero consegnare classi Java create dinamicamente per essere utilizzate da una libreria di terze parti tramite un ClassLoader personalizzato.

Ora il mio problema è: come posso impostare il mio ClassLoader personalizzato da utilizzare per caricare le classi quando non li carico direttamente da solo?

Ho pensato che quando ho usato il mio ClassLoader per caricare una determinata classe, è diventato ClassLoader di questa classe e tutte le classi caricate da quella classe sarebbero state canalizzate attraverso il mio ClassLoader.

Ho creato un ClassLoader personalizzato, seguendo questo tutorial ufficiale: 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; 
    } 
} 

ho voluto usare questo da qualche altra parte nel codice del genere:

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

Ora il mio problema è che quando chiamo findSystemClass(name) del 3 ° Class Library partito, il ClassLoader genitore trova questa classe (perché si trova sul classpath) e diventa ClassLoader. E poiché il genitore ClassLoader non conosce il mio ClassLoader personalizzato, è stato effettivamente messo fuori uso e non è possibile trasmettere this.getClass().getClassLoader() a DynamicClassLoader.

Un altro approccio sarebbe quello di impostare ClassLoader come sistema ClassLoader tramite l'argomento JVM -Djava.system.class.loader=my.DynamicClassloader. Ma che mi dà uno 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) 
    ... 

Questo deve essere davvero facile da fare, ma ora sono a corto di idee ... qualsiasi aiuto è molto apprezzato!

+0

correlati 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-contain-jars/19128964 # 191 28964 e http: // StackOverflow.com/domande/5380275/sostituzione-system-classloader-per-corsi-in-barattoli contenenti-giare. – roesslerj

risposta

19

Non sono sicuro di aver capito la domanda, si dispone di una lib di terze parti e si desidera che utilizzi il classloader per caricare le classi.

Se sei fortunato il terzo lib parte utilizza il classloader discussioni contesto quale è possibile impostare utilizzando Thread.currentThread().setContextClassLoader(myClassLoader), nello stesso thread è possibile accedere a questo programma di caricamento classe con Thread.currentThread().getContextClassLoader() ...

Un altro punto, ma non sono sicuro che è importante nel vostro contesto, è che si può anche scrivere un programma di caricamento classe genitore-ultimo che cercherà di caricare la classe prima di delegare al suo genitore (invece di cercare di delegare prima)

modificato dopo il tuo commento:

genitore_last classloader farà la differenza se la tua libreria non fa affidamento sul classloader del contesto thread, quindi devi caricare la libreria con l'ultimo genitore-genitore, impostando così il classloader come il programma di caricamento della classe invece del suo caricatore genitore (il genitore del vostro programma di caricamento classe) ...

Si può anche fare un programma di caricamento classe con un comportamento genitore-primo momento, ma per la vostra libreria di 3a parte ...

And a good link about classloaders...

+0

Il ContextClassLoader è una buona idea, lo proverò. Molte grazie! Per quanto riguarda il genitore-ultimo classloader: non penso che questo farà la differenza. In realtà non voglio definire la classe che sto caricando, voglio solo che il mio ClassLoader sia l'attuale ClassLoader, quindi tutte le successive chiamate a 'findClass' vengono canalizzate attraverso di esso ... – roesslerj

+0

Come si scrive un'ultima parent-gen loader? non c'è un'implementazione esistente? se no, allora o non è un problema comune o c'è un altro, un modo migliore per risolverlo. –

+0

Il collegamento è morto – grimmeld

Problemi correlati