Как изменить загрузчик классов по умолчанию в Java? - PullRequest
13 голосов
/ 16 июня 2011

Допустим, у меня есть три класса, example.ClassA, example.ClassB и example.ClassLoader.ClassA распечатывает HelloWorld и ClassB импортирует example.ClassA и вызывает его метод main ().Если я сделаю это:

java -cp Example.jar -Djava.system.class.loader = example.ClassLoader example.ClassA

Это работает и использует мой класспогрузчик.Однако, если я сделаю это:

java -cp Example.jar -Djava.system.class.loader = example.ClassLoader example.ClassB

ClassB использует мой классзагрузчик, но ClassA (который был импортирован ClassB) загружается с использованием загрузчика классов по умолчанию.

Есть ли способ заставить Java всегда использовать мой загрузчик классов (если явно не указан другой загрузчик классов)?

РЕДАКТИРОВАТЬ: Благодаря ответу Pa Elo Ebermann ниже, я понял, что проблема в том, что я вызываю загрузчик родительского класса (URLClassLoader), чтобы загрузить классы, к которым мне не нужно прикасаться, и эти загруженные классы устанавливают это какэто загрузчик классов контекста, поэтому импортируемые из него классы используют загрузчик родительских классов моего пользовательского загрузчика.(сбивает с толку, извините) Теперь я могу заставить его работать, читая вручную в КАЖДОМ классе, однако это кажется излишним, так как я скопировал код URLClassLoader напрямую.Есть ли способ сказать загрузчику родительского класса найти и определить класс, НО установить загрузчик класса контекста класса на свой собственный?

1 Ответ

6 голосов
/ 16 июня 2011

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

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

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

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


Идея о том, что делать:

class ModifyingClassLoader extends URLClassLoader {

    // TODO: add constructors

    private boolean needsModifying(String name) {
        // TODO
    }

    private byte[] modifyClass(InputStream original) throws IOException {
        // TODO
    }

    public Class<?> findClass(String name) throws {
        if(needsModifying(name)) {
            try {
                InputStream classData = getResourceAsStream(name.replace('.', '/') + ".class");
                if(classData == null) {
                    throw new ClassNotFoundException("class " + name + " is not findable");
                }
                byte[] array = modifyClass(classData);
                return defineClass(name, array, 0, array.length);
            }
            catch(IOException io) {
                throw new ClassNotFoundException(io);
            }
        }
        else {
            return super.findClass(name);
        }
    }
}

На ваш вопрос:

Есть ли способ указать загрузчику родительского класса найти и определить класс, НОустановить загрузчик класса контекста класса на свой?

Нет.ClassLoader класса всегда тот, чей метод defineClass был вызван для создания класса.(Загрузчик классов контекста - это нечто иное - он специфичен для потоков и используется только классами, которые явно хотят его использовать, а не классами, разрешающими свои собственные прямые зависимости.)

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