Javaagent 应用程序类未附加到变压器

标签 java javassist javaagents

我通过

使用 javaagent(带有 Javaassit)

premain(String agentArgs, Instrumentation inst)

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

简短描述:

  • 我的项目中有两个类,其中应用了 javaagent (premain)
  • MyMainClass 是具有 main 方法的类
  • MyLogicReference 类不是通过导入引用的,...在 MyMainClass
  • 仅为 MyMainClass 调用 ClassFileTransformer 转换方法,但不为 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 类。但我仍然想知道这种行为...让我们尝试一下...

for each transformer that was added with canRetransform true, the transform method is called in these transformers

详细:

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

我已将类精简为下面的一次,我想知道为什么只有 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,我就会发现调用了变压器。

So my current assumption is that only classes/subclasses which are directly referenced over the main class are send to the ClassFileTransformer. If this is correct than how can I force the javaagent to transform a class which hasn't been transformed before ?

我的 javaaagent list 条目 (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

最佳答案

根据您所说的,我猜测您是指 javaagent 代码中的MyLogicReference。因此,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 )。

关于Javaagent 应用程序类未附加到变压器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37308217/

相关文章:

java - 我将如何重新制作compareTo方法?

java - 使用 javassist 从 jar 中解析类

java - jdk 6 的 jvmti - 引用和教程

java - Java 示例的奇怪行为

java - 无法在 Java 中向经过身份验证的 Hyperledger Composer Rest 服务器发出发布请求

java - TextView 没有得到更新

hibernate - Hibernate 和 Netbeans 中的 Javassist ClassCastException

java - 使用 Javassist 插入包装原始方法逻辑的 try/finally 逻辑

java - 使用 byte-buddy-agent 修改 java.util 类

java - 如何使用代理选项记录(调试)javaagent