В настоящее время я пытаюсь изменить тела методов, находящихся в классах, уже загруженных JVM. Я знаю, что JVM фактически не позволяет изменять определение уже загруженных классов. Но мои исследования привели меня к таким реализациям, как JRebel или Java Instrumentation API, в обеих из которых используется подход на основе агентов. Я знаю, как это сделать прямо перед загрузкой класса от имени Javassist. Но учитывая, например. JRebel в среде EJB, где определения классов загружаются при запуске приложения, не должна ли модификация байт-кода быть возможной для классов, загруженных JVM?
Изменить уже загруженный класс с помощью агента Java?
Ответы (2)
Итак, вы узнали, что API инструментов существует и предлагает переопределение классов как операцию. Итак, пришло время переосмыслить исходную предпосылку «JVM фактически не позволяет изменять определение уже загруженных классов».
Вы должны отметить, что
- как показывают ссылки, Instrumentation API является частью стандартного API.
- однако поддержка переопределения классов необязательна. Вы можете спросить поддерживает ли текущая JVM эту функцию
- он может быть ограничен поддержкой всех классов; вы можете спросить возможно ли это для определенного класса
- Even if it is supported, the changes may be limited, to cite the documentation:
The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance. These restrictions maybe be lifted in future versions.
- во время выполнения переопределения могут существовать потоки, выполняющие код методов этих классов; эти выполнения будут завершены с использованием старого кода, а затем
Таким образом, инструментарий полезен только для отладки, профилирования и т. д.
Но другие фреймворки, такие как контейнеры EJB, предлагающие перезагрузку классов в производственном коде, обычно прибегают к созданию новых ClassLoader
, которые создают разные версии классов, которые затем полностью независимы от более старых версий.
В среде выполнения Java идентификатор класса состоит из пары <ClassLoader, Qualified Name>
, а не только из полного имени…
Я не знал, что вы можете использовать инструментальный API для переопределения классов (см. ответ @Holger). Однако, как он отмечает, у этого подхода есть некоторые существенные ограничения. Кроме того, в javadoc говорится:
"Этот метод предназначен для использования в приборах, как описано в спецификации класса."
Использование его для существенного изменения семантики класса... очень плохо с точки зрения системы типов Java.