Java代理:未为所有类调用transform()

Java代理:未为所有类调用transform(),transform,instrumentation,Transform,Instrumentation,我有一个非常简单的变压器: import java.io.ByteArrayInputStream; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.security.ProtectionDomain; import javassist.ClassPool; import javassist.CtClass

我有一个非常简单的变压器:

import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

//this class will be registered with instrumentation agent
public class PizzaTransformer implements ClassFileTransformer {

    public byte[] transform(ClassLoader loader, 
                            String className,
                            Class classBeingRedefined,
                            ProtectionDomain protectionDomain,
                            byte[] classfileBuffer) throws 
    IllegalClassFormatException {
        byte[] byteCode = classfileBuffer;

        System.out.println("This class is  "+className);

        return byteCode;
        }
}
代理代码如下:

import java.lang.instrument.Instrumentation;

public class PizzaAgent {
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("Executing premain.........");
        inst.addTransformer(new PizzaTransformer(),true);
    }
}
舱单是:

引导类路径:javassist.jar

课程名称:披萨代理

可以重新定义类:true

可以重新转换类:true

令人费解的是,transform()只打印了4000多个类,而通过在命令行启动时打开-verbose:class,报告加载了19000多个类

为什么超过10000个类没有调用transform()


谢谢

您只看到在连接代理时尚未加载的类。如果您也想处理加载的类,那么必须显式地重新转换这些类。您可以通过以下方式进行:

instrumentation.retransformClasses(instrumentation.getLoadedClasses());

但是,有些类是不可重传的(
Instrumentation::isModifiable
),您很可能需要拆分数组以避免耗尽内存。

可能有两种情况

  • 类尚未由JVM加载

    如果JVM尚未加载任何类,则可能不会为该类调用Java agent:transform()

    无论何时JVM加载它,Java代理都会为该类调用transform()

  • 在初始化ClassFileTransformer之前加载类

    如果您在ClassFileTransformer实现中使用了任何类或任何其他代理类,则该类可能会在ClassFileTransformer初始化之前加载,因此不会为该类调用Java Agent:transform()


  • 谢谢你的回答。但是,由于我使用的是premain方式,所以在加载任何类之前,代理不是已经添加了吗?Aka,我希望在附加代理时不会加载任何类。谢谢您的回答。但是,由于我使用的是premain方式,所以在加载任何类之前,代理不是已经添加了吗?Aka,我希望在连接代理时不会加载任何类。虽然我知道有些类是不可重构的,但应用程序类不应该是可重构的吗。在任何情况下,我都希望19000多个类都能调用transformer,这样我就可以用Instrumentation::isModifiable检查它。您的代理是用Java编写的,因此需要先加载它的类和许多系统类。是的!你是对的。有些类(如系统类)需要在代理之前加载,这是有意义的。我仍然没有看到一些应用程序类没有调用transformer。关于为什么会这样,你有什么建议吗?谢谢JVM加载类的子集,如真正需要的对象或线程。其他的,比如HttpUrlConnection,是惰性加载的。