Javaagent Application类未附加到转换器

时间:2016-05-18 19:10:15

标签: java javassist javaagents

我正在通过

使用javaagent(使用Javaassit)
  

premain(String agentArgs,Instrumentation inst)

方法,我很好奇为什么ClassFileTransformer不考虑类

简短说明:

  • 我的项目中有两个类,其中javaagent(premain)应用于
  • MyMainClass是主方法
  • 的类
  • MyLogicReference类不是通过导入引用,而是在MyMainClass
  • 中引用
  • ClassFileTransformer转换方法仅针对MyMainClass调用,但不针对MyLogicReference调用
  • 如果我调用java.lang.instrument.Instrumentation getAllLoadedClasses,那么我可以看到MyLogicReference类已加载
  • ?这是代理的工作方式,如果是,我怎样才能使代理转换第二个(MyLogicReference)类?

更新

我想我在Javadocs https://docs.oracle.com/javase/7/docs/api/java/lang/instrument/ClassFileTransformer.html中找到了一些有用的信息。

在java.lang.instrument.Instrumentation.retransformClasses中,我应该可以从示例中注册MyLogicReference类。但我仍然对这种行为感到疑惑......让我们尝试一下......

  对于添加了canRetransform true的每个变换器,

  在这些变换器中调用transform方法

详细说明:

我正在使用代理来改变方法,...通过注释(某种注入)。

我已经将类拆除为下面的onces,我想知道为什么只有MyMainClass被放到javaagent转换器(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 method

我可以看到MyLogicReference类。但是从未为此类调用ClassFileTransformer。这对javaagents是否正确?

如果我,例如在MyMainClass中导入MyLogiReference.class,我发现调用了变换器。

  

所以我目前的假设是只有类/子类   直接引用主类被发送到   ClassFileTransformer 即可。如果这是正确的,我怎么强迫   javaagent转换一个之前没有被转换过的类?

我的javaaagent清单条目(MVN):

<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

1 个答案:

答案 0 :(得分:0)

根据您的说法,我猜您在javaagent代码的某个地方指的是 MyLogicReference 。因此,JVM在检测开始之前加载类。要记住两件事:

  1. Java代理只是一个java程序,它需要加载类。
  2. Java代理在加载时转换类。对于在java代理启动之前加载的任何类,您将需要使用 java.lang.instrument.Instrumentation #revertformClasses (正如您自己注意到的那样)。
  3. 使用 java.lang.instrument.Instrumentation #revertformClasses 在这里似乎也没有必要。在我看来,最好避免它(为了简单起见)。你可以:

    • 分隔javaagent使用的代码和正在检测的代码。
    • 仅将 MyLogicReference 称为字符串,例如。使用foo.getClass().getName().equals("MyLogicReference")代替foo instanceof MyLogicReference

    根据提供的信息,我还想知道您是否考虑使用注释处理器(https://docs.oracle.com/javase/7/docs/api/javax/annotation/processing/Processor.html)。