Итак, у меня есть classloader (MyClassLoader), который поддерживает набор "специальных" классов в памяти. Эти специальные классы динамически компилируются и хранятся в массиве байтов внутри MyClassLoader. Когда MyClassLoader запрашивает класс, он сначала проверяет, содержит ли его словарь specialClasses
, прежде чем делегировать загрузку класса System. Это выглядит примерно так:
class MyClassLoader extends ClassLoader {
Map<String, byte[]> specialClasses;
public MyClassLoader(Map<String, byte[]> sb) {
this.specialClasses = sb;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (specialClasses.containsKey(name)) return findClass(name);
else return super.loadClass(name);
}
@Override
public Class findClass(String name) {
byte[] b = specialClasses.get(name);
return defineClass(name, b, 0, b.length);
}
}
Если я хочу выполнить преобразования (например, инструментальные средства) в specialClasses
, я могу сделать это просто, изменив byte[]
до того, как я назову defineClass()
на нем.
Я также хотел бы преобразовать классы, которые предоставляются загрузчиком класса System, но загрузчик классов System не предоставляет никакого доступа к исходному byte[]
классам, которые он предоставляет, и дает мне Class
объекты напрямую.
Я мог бы использовать инструмент -javaagent
для всех классов, загружаемых в JVM, но это добавило бы накладные расходы к классам, которые я не хочу использовать; Я действительно хочу, чтобы классы, загруженные MyClassLoader, были инструментальными.
- Есть ли способ получить исходный
byte[]
классов, предоставляемых родительским загрузчиком классов, поэтому я могу настроить их перед определением моей собственной копии? - Альтернативно, существует ли какой-либо способ эмуляции функциональных возможностей загрузчика класса System, с точки зрения того, где он захватывает его
byte[]
, так что MyClassLoader может определять и определять свою собственную копию всех классов системы (Object, String, и др.)?
EDIT:
Итак, я попробовал другой подход:
- Используя
-javaagent
, запишитеbyte[]
каждого загружаемого класса и сохраните его в хеш-таблице, с именем имени класса. - MyClassLoader вместо делегирования системных классов к его родительскому загрузчику классов вместо этого загрузит свой байт-код из этой хэш-таблицы с использованием имени класса и определит его
В теории это позволит MyClassLoader определить собственную версию системных классов с инструментами. Однако с ошибкой
java.lang.SecurityException: Prohibited package name: java.lang
Ясно, что JVM не любит, чтобы я сам определял классы java.lang
, хотя он должен (теоретически) быть из того же источника byte[]
, из которого должны были загружаться классы, загруженные с начальной загрузки. Поиск решения продолжается.
EDIT2:
Я нашел (действительно отрывочное) решение для этой проблемы, но если кто-то, кто знает больше, чем я о тонкостях загрузки/инструментария Java-класса, может придумать что-то менее отрывочное, это было бы потрясающе.