Можно ли действительно заменить загрузчик классов Java System?
В Java есть свойство -Djava.system.class.loader для замены загрузчика системных классов.
Однако любой класс, созданный с использованием новый, а не .newInstance(), показывает AppClassLoader в качестве загрузчика классов.
AppClassLoader также известен как загрузчик системных классов, поэтому не похоже, что происходит какая-либо реальная замена.
Например, при запуске (Oracle Hotspot в Windows JDK 1.8)
// Run with java -Djava.system.class.loader=classLoaders.MyClassLoader Example
public class MyClassLoader extends ClassLoader {
public MyClassLoader(ClassLoader parent) {
super(parent);
}
@Override
public Class loadClass(String name) throws ClassNotFoundException {
System.out.println("Loading class :" + name);
return super.loadClass(name);
}
}
class A {
}
public class Example {
public static void main(String[] args) throws Exception {
System.out.println(ClassLoader.getSystemClassLoader());
System.out.println(new Example().getClass().getClassLoader());
System.out.println(new A().getClass().getClassLoader());
}
}
Результат:
Loading class :classLoaders.Example
classLoaders.MyClassLoader@6d06d69c
sun.misc.Launcher$AppClassLoader@58644d46
sun.misc.Launcher$AppClassLoader@58644d46
Пока первый экземпляр Example загружается с помощью MyClassLoader, а метод getSystemClassLoader возвращает MyClassLoader, любой класс, созданный с помощью новый, загружается исходным загрузчиком системных классов, так что именно заменяется?




Вам следует переопределить метод toString () вашего MyClassLoader и посмотреть, работает ли он.
В самой ранней последовательности загрузки JVM должен быть загрузчик классов для загрузки класса, переопределяющего загрузчик классов. Для этого также должен быть загружен ряд других классов, чтобы реализовать первоначальный загрузчик классов и построить достаточно JVM, чтобы должным образом принять перезаписанный загрузчик классов.
После того, как загрузчик классов был успешно переопределен, он должен вызывать ваше переопределение для остальных классов.
Это означает, что вы должны позаботиться о том, чтобы ранние вызовы загрузчика классов нереализованной версии не воспринимались как ошибки.
Вы просто расширяете ClassLoader и используете super.loadClass(); Итак, какой-то другой настоящий загрузчик классов выполняет фактическую загрузку класса.
За кулисами кажется, что система передает свои полномочия загрузчику классов System после того, как вы перейдете к загрузке.
Здесь уже дан ответ на тот же вопрос: https://stackoverflow.com/a/25493910/1364747
A class loader L may create C by defining it directly or by delegating to another class loader. If L creates C directly, we say that L defines C or, equivalently, that L is the defining loader of C.
When one class loader delegates to another class loader, the loader that initiates the loading is not necessarily the same loader that completes the loading and defines the class. If L creates C, either by defining it directly or by delegation, we say that L initiates loading of C or, equivalently, that L is an initiating loader of C.
At run time, a class or interface is determined not by its name alone, but by a pair: its binary name (§4.2.1) and its defining class loader. Each such class or interface belongs to a single run-time package. The run-time package of a class or interface is determined by the package name and defining class loader of the class or interface.
Хотя MyClassLoader вызывает super.loadClass, реализация ClassLoader-> loadClass только находит другой экземпляр и делегирует ему полномочия.
Таким образом, реализация родительского класса только передает задание другому экземпляру.
Нет, дело не в этом. Например, определение класса A {} и использование New никогда не достигает System.out.println внутри MyClassLoader, что до делегирования
Класс загружается только один раз. Пример уже загружен. Итак, он больше не загружается. Это могло быть причиной. Возможно, вам придется попробовать другой общедоступный класс в том же пакете. Потом проверьте результат.
В конце концов, загрузка Example была делегирована AppClassLoader. Итак, все "новое" изнутри Example будет поступать только в AppClassLoader. Возможно :) Попробуйте загрузить один байт класса самостоятельно. И делегирую другому ..
Вероятно, поэтому вместо наследования используется делегирование. Так что loadClass любого родительского загрузчика может быть вызван извне.
Отвечает ли это на ваш вопрос? Почему не работает пользовательский системный загрузчик классов?