Как поставить пользовательский ClassLoader для использования? - PullRequest
28 голосов
/ 04 ноября 2010

Привет всем и спасибо за внимание!У меня есть проблема, которая должна быть простой и очевидной, но я застрял.

Я хочу доставить динамически созданные классы Java для использования сторонней библиотекой через пользовательский ClassLoader.

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

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

Я создал собственный ClassLoader, следуя этому официальному учебнику: 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;
    }
}

Я хотел использоватьэто где-то еще в коде, подобном этому:

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

Теперь моя проблема заключается в том, что когда я вызываю findSystemClass(name) из стороннего библиотечного класса, родительский ClassLoader находит этот класс (потому что он находится в пути к классам)и становится его ClassLoader.И поскольку родительский ClassLoader не знает о моем пользовательском ClassLoader, он фактически выведен из использования и this.getClass().getClassLoader() не может быть приведен к DynamicClassLoader.

Другой подход заключается в том, чтобы установить мой ClassLoader в качестве системыClassLoader через аргумент JVM -Djava.system.class.loader=my.DynamicClassloader.Но это дает мне 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)
    ...

Это должно быть очень легко сделать, но у меня сейчас нет идей ... любая помощь очень ценится!

1 Ответ

21 голосов
/ 04 ноября 2010

Не уверен, что я понимаю вопрос, у вас есть сторонняя библиотека, и вы хотите, чтобы она использовала ваш загрузчик классов для загрузки классов.

Если вам повезет, сторонняя библиотека использует загрузчик классов для контекста потоков, который выможно установить с помощью Thread.currentThread().setContextClassLoader(myClassLoader), в том же потоке вы можете получить доступ к этому загрузчику классов с помощью Thread.currentThread().getContextClassLoader() ...

Еще один момент, но не уверен, что это важно в вашем контексте, это то, что вы также можете написать родительскийПоследний загрузчик классов, который попытается загрузить класс перед делегированием его родителю (вместо попытки делегировать сначала)

Отредактировано после вашего комментария:

parent_last classloader сделаетразница, если ваша библиотека не полагается на загрузчик классов контекста потока, тогда вы должны загрузить библиотеку с вашим последним родительским загрузчиком классов, тем самым установив ваш загрузчик классов в качестве загрузчика классов для библиотеки вместо ее родительского загрузчика (родителя вашего загрузчика классов)...

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

И хорошая ссылка о загрузчиках классов ...

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