Question

Je suis en train de changer le chargeur de classe lors de l'exécution:

public class Test {
    public static void main(String[] args) throws Exception {
        final InjectingClassLoader classLoader = new InjectingClassLoader();
        Thread.currentThread().setContextClassLoader(classLoader);
        Thread thread = new Thread("test") {
            public void run() {
                System.out.println("running...");
                // approach 1
                ClassLoader cl = TestProxy.class.getClassLoader();
                try {
                    Class c = classLoader.loadClass("classloader.TestProxy");
                    Object o = c.newInstance();
                    c.getMethod("test", new Class[] {}).invoke(o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // approach 2
                new TestProxy().test();
            };
        };
        thread.setContextClassLoader(classLoader);
        thread.start();
    }
}

et

public class TestProxy {
    public void test() {
        ClassLoader tcl = Thread.currentThread().getContextClassLoader();
        ClassLoader ccl = ClassToLoad.class.getClassLoader();
        ClassToLoad classToLoad = new ClassToLoad();
    }
}

( InjectingClassLoader est une classe extension de la org.apache.bcel.util.ClassLoader qui devrait charger les versions modifiées des classes avant de demander à des parents de pour eux)

Je voudrais faire le résultat de « l'approche 1 » et « 2 approche » exactement le même, mais il semble que thread.setContextClassLoader (classLoader) ne fait rien et l'approche « 2 » toujours utilise le chargeur de classe de système (peut être déterminée en comparant les variables de tcl et CCL pendant le débogage).

Est-il possible de faire toutes les classes chargés par la nouvelle utilisation de fil classloader donné?

Était-ce utile?

La solution

La classe anonyme que vous créez via new Thread("test") { ... } a une référence implicite à l'instance englobante. Classe littéraux dans cette classe anonyme seront chargés à l'aide de ClassLoader de la classe englobante.

Pour faire fonctionner ce test, vous devez retirer une mise en œuvre correcte Runnable, et le charger en utilisant pensivement la ClassLoader désirée; passer alors que explicitement au fil. Quelque chose comme:

    public final class MyRunnable implements Runnable {
        public void run() {
            System.out.println("running...");
            // etc...
        }
    }

    final Class runnableClass = classLoader.loadClass("classloader.MyRunnable");
    final Thread thread = new Thread((Runnable) runableClass.newInstance());

    thread.setContextClassLoader(classLoader); // this is unnecessary unless you you are using libraries that themselves call .getContextClassLoader()

    thread.start();

Autres conseils

Je pense que InjectingClassLoader peut être important. Rappelez-vous comment fonctionne la délégation classloading - si plus d'un classloader dans la hiérarchie peut trouver la classe, le sommet le plus classloader sera celui qui se charge. (Voir Figure 21.2 )

Depuis InjectingClassLoader ne spécifie pas un parent dans son constructeur, il sera par défaut au constructeur dans le ClassLoader abstrait, qui établira le classloader de contexte en tant que parent de InjectingClassLoader. Par conséquent, puisque le parent (ancien classloader contexte) peut trouver TestProxy, il a toujours charge la classe avant InjectingClassLoader obtient une chance de.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top