Reflection CtMethod如何影响类加载?CtMethod.insertBefore()无效

Reflection CtMethod如何影响类加载?CtMethod.insertBefore()无效,reflection,classloader,bytecode,instrumentation,javassist,Reflection,Classloader,Bytecode,Instrumentation,Javassist,请跟着读。我有一个Lion类,它有一个方法stayLion public class Lion { //class Variables and methods public void stayLion(String temp,int temp2,double temp3, boolean temp4,Food food) throws InterruptedException { //method Body } } 该方法将食品实例作为其参数之一。食品类有coo

请跟着读。我有一个
Lion
类,它有一个方法
stayLion

public class Lion {
    //class Variables and methods
    public void stayLion(String temp,int temp2,double temp3, boolean temp4,Food food) throws InterruptedException {
    //method Body
    }
}
该方法将
食品
实例作为其参数之一。食品类有
cook
方法

public class Food{
    public void cook(){
    }
}
我正在尝试使用这两种方法,
stayLion
cook
JVM加载的每个类都会调用transform方法。(我想知道,在哪里,谁调用它。如果我错了,请纠正我)如果类名与我想要的类名列表匹配,我将提取方法列表,并验证methodName及其参数,我找到了我希望使用的方法(stayLion和cook)的CtMethod实例

但是,在验证
stayLion
参数的过程中,加载了
Food
类,并且没有调用转换方法(我不知道原因。类加载程序是相同的。为什么在加载Food类时没有调用transform方法?)。为了克服这个问题,我显式地调用
transform
method for
Food
类(一般来说,每当我希望检测其方法的类位于我还希望检测的任何其他方法的参数列表中时,我都会调用
transform
方法)

但是这种对transform方法的显式调用是无效的。准确地说,

ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.getCtClass(className.replace("/","."));
CtMethod[] methods = ctClass.getDeclaredMethods();
在此之前,
methods
包含食品类所有方法的列表。验证无参数的
cook
方法后

for (CtMethod method : methods) {
    //verifying method (name and parameter)
    method.insertBefore( //some code );
}

但此时,
method.insertBefore()
无效,并且没有向所需的方法添加任何代码。

JVM在类加载或重新定义期间调用
transform
方法。除非您正在测试,否则直接调用该方法没有多大意义

如果在代码操作期间加载类,则不会转换正在加载的类。这是为了避免插装
A
加载
B
和插装
B
加载
A
时插装中出现循环。如果您试图加载插入指令的类本身,这将导致
类循环错误


我假设,当您输入
Lion
时,您在处理参数时正在加载
Food
。通过使用Javassist,您通常可以避免这种情况,因为Javassist直接加载类文件,但我认为您是在某处引用
Lion
类作为常量,因此将其加载到转换器中的某个位置。

我理解,在插入代码的过程中,如果我调用
transform
,存在无限循环的风险。我有一个适当的基本情况来避免这种情况。我正在main方法中创建一个
Lion
类的实例。它加载并检测相应的方法。然而,就在那之后,我还制作了
食品
类的实例,该类也被期望通过相同的路径进行检测。但是,它不会发生,因为它是在检测
Lion
的过程中加载的。我怎样才能避免这种情况??感谢您的帮助,您可以使用
Instrumentation::retransformClasses
方法在加载的类上应用类文件转换器。您必须在代理的清单中启用此功能。请确保在重新传输时不更改类的签名。我不确定从何处以及如何调用此
retransformClasses
方法。或者,我维护了一个映射,该映射将类名对应于类的类名,这些类是需要插入指令的方法的参数,它们本身也在需要插入指令的类的列表中。这样,当我为
Lion
输入
transform
方法时,我看到地图,找到
Food
类作为它的依赖项之一,此时,请尝试调用
transform
方法。安装类文件转换器后,将布尔
canRetransform
参数设置为true,然后从代理调用该方法。
public static void premain(String agentArgs,Instrumentation inst)抛出不可修改的类异常{System.out.println(“启动premain………”;ConfigObj ConfigObj=getConfig(agentArgs);inst.addTransformer(新DurationTransformer2(ConfigObj),true);inst.retransformClasses(ConfigObj.getClasses());System.out.println(“结束premain!\n”);}
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.getCtClass(className.replace("/","."));
CtMethod[] methods = ctClass.getDeclaredMethods();
for (CtMethod method : methods) {
    //verifying method (name and parameter)
    method.insertBefore( //some code );
}