2016-05-18 3 views
3

Я использую javaagent (с Javaassit) черезкласса Javaagent Применения не подключен к трансформатору

premain (String agentArgs, Инструментарий INST)

метод и я диковинку, почему класс не рассматривается ClassFileTransformer

Краткое описание:

  • У меня есть два класса, в моем проекте, где javaagent (premain) применяется к
  • MyMainClass класс с основным методом
  • MyLogicReference класс не ссылки через импорт, ... в MyMainClass
  • ClassFileTransformer метод преобразования вызывается только для MyMainClass но не для MyLogicReference
  • Если я называю java.lang.instrument.Instrumentation getAllLoadedClasses, то я могу видеть, что класс MyLogicReference загружен
  • ? Так работает агент, и если да, как я могу агенту преобразовать второй класс (MyLogicReference)?

UPDATE

Я думаю, я нашел некоторую полезную информацию в Javadocs https://docs.oracle.com/javase/7/docs/api/java/lang/instrument/ClassFileTransformer.html.

В java.lang.instrument.Instrumentation.retransformClasses Я должен иметь возможность зарегистрировать класс MyLogicReference из примера. Но я до сих пор задаюсь вопрос о поведении ... Попробую это ...

для каждого трансформатора, который был добавлен с canRetransform правда, метода преобразования называется в этих трансформаторах

детальных :

Я использую агент для изменения методов, ... посредством аннотаций (некоторая инъекция).

Я разделил классы только на onces ниже, и мне интересно, почему только MyMainClass помещается в javaagent transformer (classfilebuffer), но не в класс MyLogicReference.

public class MyMainClass { 

    ... //Main method and call of myMethod();  

    @MyAnnotationToApplyLogic 
    public void myMethod(){ 
    //Some code here 
    } 

Точка входа для моего процесса, чтобы изменить код является аннотацией, где я отсылаю к другому классу (MyLogicReference) ...

@Documented 
@Target(ElementType.PARAMETER) 
@Retention(RetentionPolicy.CLASS) 
@Functional(value = MyLogicReference.class, type = ElementType.PARAMETER) 
public @interface MyAnnotationToApplyLogic { 

} 

public class MyLogicReference { 
    // @MyAnnotationToApplyLogic in the MyMainClass method references to this class 
    // The Javaagent Class file transformer adjust the MyMainClass.myMethod code based on the annotation 
    public void mySecondMethod(){ 
    } 
} 

Если я использую

Java. lang.instrument.Instrumentation getAllLoadedClasses метод

Я могу видеть класс MyLogicReference.Но ClassFileTransformer никогда не вызывается для этого класса. Правильно ли это для javaagents?

Если я, например, импортирую класс MyLogiReference.class в MyMainClass, я понял, что вызывается трансформатор.

Так мое текущее предположение, что только классы/подклассы, которые непосредственно ссылаются на главный класс отправляются в ClassFileTransformer. Если это правильно, то как я могу заставить javaagent преобразовать класс, который раньше не преобразовывался?

Мои javaaagent манифеста записи (МВН):

<Premain-Class>com.MyTestAgent</Premain-Class> 
<Agent-Class>com.MyTestAgent</Agent-Class> 
<Can-Redefine-Classes>true</Can-Redefine-Classes> 
<Can-Retransform-Classes>true</Can-Retransform-Classes> 

Я раздели вниз ClassFileTransformer к этому, и второй класс еще не загружен:

@Override 
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { 
    if (!className.startsWith("java/") && !className.startsWith("javax/") && !className.startsWith("sun/")) { 
    log("NOW PROCESSING: " + className); 
    return classfileBuffer; 
    } 
    return null; 
} 

//Output: 
//NOW PROCESSING: MyMainClass 

ответ

0

На основании того, что вы сказал, что я предполагаю, что вы ссылаетесь на MyLogicReference где-то из вашего кода javaagent. Как следствие, JVM загружает класс до начала работы инструментария. Две вещи, которые следует помнить:

  1. Java-агент - это просто программа Java, и для этого требуются классы для загрузки.
  2. Java-агент преобразует классы при их загрузке. Для любого класса, загруженного до запуска java-агента, вам нужно будет использовать java.lang.instrument.Instrumentation # retransformClasses (как вы заметили сами).

Использование java.lang.instrument.Instrumentation # retransformClasses не представляется необходимым здесь. По-моему, всегда лучше избегать этого (ради простоты). Вы можете:

  • Отделите код, который используется javaagent, и код, который используется для инструментов.
  • относится только к MyLogicReference как строка, например. использовать foo.getClass().getName().equals("MyLogicReference") вместо foo instanceof MyLogicReference

На основании предоставленной информации, я также интересно, если вы рассматривали использование аннотаций процессора вместо (https://docs.oracle.com/javase/7/docs/api/javax/annotation/processing/Processor.html).

+0

Спасибо за ответ. Я уже посмотрел на обработчики аннотаций (не подробно). Когда дело доходит до модификации кода и не создавайте классы прокси, я предпочитаю агент перед anno. процессор с хаками (вроде loombok). Кроме того, сфера действия агента заключается в том, что мои утилиты выходят из строя (например, удаленный JMX, ...). С другой стороны, для действий, связанных с аннотацией, процесс хорош (с компиляцией сообщений, ...). Для меня, как новичка в этих темах, обработчик аннотации с методом преобразования был бы большим: D –