Java: получение байт-кода класса во время выполнения из одного JVM
Связано с: Есть ли способ получить байт-код для класса во время выполнения?
Я добавляю долговечность к Clojure, и я, наконец, готов к тому, чтобы добавить функции. В Clojure функции байт компилируются в классы с помощью методов invoke (среди прочих). Таким образом, функции являются первоклассными. Чтобы сделать эти прочные, мне нужно сериализовать и десериализовать эти классы. Как получить байт-код для класса без доступа к файлу .class?
Пожалуйста, исправьте меня, если я ошибаюсь, но при использовании агента требуется разворачивание отдельной виртуальной машины с агентом, подключающимся к первой виртуальной машине. Мне нужно сделать это с той же виртуальной машины.
Недостаточно использовать Serializable для установки и получения объекта Class. При десериализации мне нужно загрузить класс, а после последующих экземпляров VM может возникнуть конфликт имен классов. Мне нужно изменить байт-код, чтобы переименовать класс в нечто уникальное при десериализации/времени загрузки класса.
Ответы
Ответ 1
Вы можете написать свой собственный ClassLoader
и взломать схему, которая записывает байт-код при загрузке классов.
Вам нужно будет переопределить findClass
, чтобы найти файл класса самостоятельно, загрузить его в память, сохранить данные где-нибудь (для последующей сериализации), а затем вызвать defineClass
, чтобы определить этот класс в JVM.
Ответ 2
Если вы не запускаете код через сложный загрузчик классов, вы должны сделать что-то вроде этого:
Class<?> clazz = ....
String className = clazz.getCanonicalName(); // e.g. "foo.Bar"
String resourceName = ... // map className to a resource name; e.g. "/foo/Bar.class"
InputStream is = clazz.getClassLoader.getResourceAsStream(resourceName);
Это дает вам описание содержимого файла ".class"... если оно может быть найдено.
предостережений. Некоторые загрузчики классов могут:
- не позволяет открывать ресурсы ".class" вообще,
- предоставит вам зашифрованный поток байт-кода или
- предоставляют вам байт-коды, которые не являются точно тем, что выполняется, из-за некоторого "на лету" преобразования, выполняемого загрузчиком классов.
Если этот подход не работает, вы практически не используете параметры, потому что JVM не предоставляет способ доступа к фактическим байт-кодам, которые были загружены.
Ответ 3
Для этого также можно использовать Java Instrumentation API. Вы получаете доступ к байтам файла классов перед вызовом defineClass. Вы также можете изменить их!