Подтвердить что ты не робот

Как изменить загрузчик классов по умолчанию в Java?

Скажем, у меня есть три класса: example.ClassA, example.ClassB и example.ClassLoader. ClassA выводит пример импорта HelloWorld и ClassB.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 всегда использовать мой загрузчик классов (если явно не указан другой загрузчик классов)?

EDIT: Спасибо Paŭlo Ebermann ниже, я решил, что проблема заключается в том, что я вызываю загрузчик родительского класса (URLClassLoader) для загрузки классов, которые мне не нужно касаться, и эти загруженные классы устанавливают это как загрузчик контекстного класса, поэтому классы, импортированные из него, используют загрузчик родительского класса моего пользовательского загрузчика. (сбивает с толку, извините) Теперь я могу заставить его работать с помощью ручного чтения в классе EVERY, однако он кажется лишним, поскольку я скопировал код URLClassLoader напрямую. Есть ли способ рассказать загрузчику родительского класса, чтобы найти и определить класс, но установить загрузчик класса контекстного класса Class на свой собственный?

4b9b3361

Ответ 1

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

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

Все классы, определенные вашим загрузчиком классов, также будут искать нужные классы в вашем загрузчике классов. Если они этого не делают, ваш 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);
        }
    }
}

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

Есть ли способ сообщить загрузчику родительского класса найти и определить класс, BUT установил загрузчик класса контекстного класса Class на свой собственный?

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