2013-11-27 4 views
1

Как поставщик API Framework с открытым исходным кодом для жизненного цикла, я хочу изо всех сил стараться скрывать внутренние проекты с помощью неявного способа предоставления API Lifecycle, чтобы принесет гораздо больше удобств для API-клиента.Есть ли какое-либо решение в отношении преобразования времени байта в нагрузку без указания опции javaagent в командной строке java

Ожидается, что он не будет выполнять конфигурацию как для основных приложений Java, так и для приложений Java EE, но в действительности я использую команду java -javaagent: $ {path} /Lifecycle.jar, чтобы включить собственный класс ClassFileTransformer в классе время загрузки.

После некоторых поисков были обнаружены некоторые неясные направления. Мне нужен Java Guy для обобщения и руководства.

  1. agentmain против premain
  2. Интеграция с заданной среды выполнения, такие как ByteCodePreprocessor GlassFish, который имеет следующий метод для выполнения преобразования байт-код:

    public byte[] preprocess(String classname, byte[] classBytes);

Мои неурядицы о эти направления:

  1. Для основного приложения Java кажется, что мы можем изменить основной метод класса запуска для адаптации решения agentmain. Есть ли другие варианты?
  2. Для использования контейнера JavaEE, такого как Glassfish, я могу использовать ByteCodePreprocessor для изменения класса байтового кода, но мне нужно создать несколько новых классов, но я не знаю, где хранить эти новые файлы классов или как проектировать или применить новый ClassLoader для загрузки вновь созданных файлов классов во время предварительной обработки файла класса.

(BTW Lifecycle API будет следовать мета-управляемый стиль, который очень близок с JPA без интерфейса EntityManager, и большинство из них является только аннотаций и CallbackContext интерфейс и интерфейс LifecycleEvent на данный момент.)

+0

Хотя вы уже отметили ответ как решение, вы можете взглянуть на [javassist] (http://www.csg.ci.iu-tokyo.ac.jp/~chiba/javassist/), который в основном обеспечивает манипулирование байтами класса и встраивание дополнительных инструкций Java в классы, конструкторы и методы. Чтобы увидеть это в действии, вы можете взглянуть на [простую схему плагинов] (https://github.com/RovoMe/PluginApplication/blob/master/PluginFramework/PluginCore/src/main/java/at/rovo/core/ classloader/InjectionLoaderStrategyDecorator.java) Я написал для университетского курса. –

ответ

2

Ну , единственный другой метод, о котором я мог подумать, будет использовать пользовательский загрузчик классов, который вы могли бы зарегистрировать во время выполнения. Вот как такие каркасы, как Powermock, делают свой тяжелый подъем. Однако это требует некоторой настройки, но это можно сделать программно.

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

Однако это не будет работать для уже загруженных классов. (Вы можете сломать родительский первый патерн, но это может привести к возникновению ClassCastException s в случаях извне вашей рамки.)

Избегая этого, вам потребуется переопределить загрузчик системного класса, который является одинаково подробным. Для полноты картины, вот выдержка из Javadoc из ClassLoader.getSystemClassLoader:

Если системное свойство «java.system.class.loader» определяется, когда этот метод вызывается первым, то значение этого свойства принято считать именем класса, который будет возвращен в качестве загрузчика системного класса. Класс загружается с использованием загрузчика системного класса по умолчанию и должен определить публичный конструктор, который принимает один параметр типа ClassLoader, который используется в качестве родителя делегирования. Экземпляр - это , затем созданный с использованием этого конструктора со стандартным системным классом загрузчиком в качестве параметра. Результирующий загрузчик классов определяется как загрузчик системного класса.

В этом пользовательском загрузчике классов вы всегда можете вернуть инструментальные классы.

difference between agentmain and premain - это то, что первое вызывается при подключении агента к запущенной JVM (via the attach API), в то время как последний вызывается, если агент указан в командной строке при запуске JVM. Регистрация агента во время выполнения может стать для вас решением. Запись в блоге, которую я связывал, дает неплохое описание этого.

+0

Спасибо, Raphw. Я читал ваш ответ очень внимательно несколько раз. И я прочитал все ссылки, которые вы предоставили. Наконец, я думаю, что у меня есть твои идеи для моих проблем. –

+0

Спасибо, Raphw. Я читал ваш ответ очень внимательно несколько раз. И я прочитал все ссылки, которые вы предоставили. Наконец, я думаю, что у меня есть твои идеи для моих проблем. Чтобы динамически загружать агент lib, мне нужно выполнить некоторый код перед загрузкой классов приложений: для приложения Core Java я могу просто изменить основной класс. А для приложения JavaEE я могу использовать событие жизненного цикла контейнера для загрузки контейнера агента. А для создания и загрузки новых инструментальных классов я могу использовать java.system.class.loader. Есть ли какое-либо другое соображение при использовании двух методов, которые я обобщил из вашего ответа? –

+0

Вот что я пытался выразить. Когда вы запускаете классы после запуска приложения, почти невозможно загрузить классы инструментов, которые уже были загружены. Однако вы можете зарегистрировать агента после запуска программы (например: http://dhruba.name/2010/02/07/creation-dynamic-loading-and-instrumentation-with-javaagents/), этот агент позволяет вам помешать любым классы, которые еще не загружены. Если ваша структура имеет четко определенную точку входа, вы можете просто зарегистрировать этот агент один раз. (например, некоторый метод 'Framework.initialize()') –