Цепная загадка загрузчика классов - PullRequest
1 голос
/ 06 февраля 2012

У меня трудные времена с загрузчиками классов Java, возможно, кто-то может пролить свет на это Я раскрыл суть проблемы следующим образом:

Есть три класса - ClassLoaderTest, LoadedClass и LoadedClassDep. Они все на разных путях.

ClassLoaderTest создает новый URLClassLoader - myClassLoader, заполняя его путями к оставшимся двум классам и своим собственным загрузчиком классов (то есть загрузчиком классов приложения) в качестве родительского. Затем он использует Class.forName("com.example.LoadedClass", true, myClassLoader) для загрузки LoadedClass через отражение. LoadedClass импортирует LoadedClassDep. Если я запускаю выше, используя:

java -cp /path/to/the/ClassLoaderTest ClassLoaderTest "/path/to/LoadedClass" "/path/to/LoadedClassDep"

и используя аргументы командной строки для простого URLClassLoader все работает нормально. Используя статические инициализаторы, я подтверждаю, что два класса загружены с экземпляром URLClassLoader. ОДНАКО, и это проблема, если я сделаю:

java -cp /path/to/the/ClassLoaderTest:/path/to/the/LoadedClass ClassLoaderTest "/path/to/LoadedClassDep"

Не удается загрузить LoadedClassDep (ClassNotFoundException). LoadedClass загружен правильно, но с sun.misc.Launcher$AppClassLoader, а не URLClassLoader! Казалось бы, поскольку загрузчик классов приложения способен загружать LoadedClass, он также пытается загрузить LoadedClassDep, игнорируя URLClassLoader.

Вот полный исходный код:

</p>

<code>package example.bc;
public class ClassloaderTest {
    public static void main(String[] args) {
        new ClassloaderTest().run(args);
    }

    private void run(String[] args) {
        URLClassLoader myClasLoader = initClassLoader(args);
        try {
            Class<?> cls = Class.forName("com.example.bc.LoadedClass", true, myClasLoader);
            Object obj = cls.newInstance();
            cls.getMethod("call").invoke(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private URLClassLoader initClassLoader(String[] args) {
        URL[] urls = new URL[args.length];

        try {
            for (int i = 0; i < args.length; i++) {
                urls[i] = new File(args[i]).toURI().toURL();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return new URLClassLoader(urls, getClass().getClassLoader());
    }
}

package com.example.bc;

import com.bc.LoadedClassDep;

public class LoadedClass {

    static {
        System.out.println("LoadedClass " + LoadedClass.class.getClassLoader().getClass());
    }

    public void call() {
        new LoadedClassDep();
    }
}

package com.bc;

public class LoadedClassDep {
    static {
        System.out.println("LoadedClassDep " + LoadedClassDep.class.getClassLoader().getClass());
    }
}
</code>

Надеюсь, я прояснил это достаточно. Моя проблема в том, что я знаю только путь к ClassLoadeTest во время компиляции, я должен использовать строки во время выполнения для других путей. Итак, есть идеи, как заставить работать второй сценарий?

1 Ответ

1 голос
/ 06 февраля 2012

Я ожидаю, что загрузчик классов приложения загрузит LoadedClass во втором случае, поскольку загрузчики классов изначально делегируют своим родителям - это стандартное поведение . Во втором случае LoadedClass находится на пути к классу родителя, поэтому он загружает класс вместо того, чтобы сдаться и позволить URLClassLoader попробовать.

Затем загрузчик классов приложения пытается загрузить LoadedClassDep, поскольку он импортируется и на него ссылаются непосредственно в LoadedClass:

public void call() {
    new LoadedClassDep();
}

Если вам нужно загружать эти классы динамически и независимо во время выполнения, вы не можете иметь прямые ссылки между ними таким образом.

Также возможно изменить порядок, в котором используются загрузчики классов - см. Загрузчики классов Java: зачем сначала искать родительский загрузчик классов? , чтобы обсудить это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...