解决JNI中的依赖关系DefineClass

问题描述:

我正在使用JVMTI编写应用程序。我正在尝试使用字节码:通过在每个方法条目上注入方法调用。解决JNI中的依赖关系DefineClass

我知道该怎么做,但问题出在仪器类上,比如说它叫做Proxy,我用JNI函数DefineClass加载。我的Proxy在Java类库中有一些依赖关系,目前只有java.lang.ThreadLocal<Boolean>

现在,说我有这个,其中inInstrumentMethod是一个普通的boolean

public static void onEntry(int methodID) 
{ 
    if (inInstrumentMethod) { 
     return; 
    } else { 
     inInstrumentMethod = true; 
    } 

    System.out.println("Method ID: " + methodID); 

    inInstrumentMethod = false; 
} 

代码编译和作品。但是,如果我使inInstrumentMethod a java.lang.ThreadLocal<Boolean>,我得到一个NoClassDefFoundError。代码:

private static ThreadLocal<Boolean> inInstrumentMethod = new ThreadLocal<Boolean>() { 
     @Override protected Boolean initialValue() { 
      return Boolean.FALSE; 
     } 
    }; 

public static void onEntry(int methodID) 
{ 
    if (inInstrumentMethod.get()) { 
     return; 
    } else { 
     inInstrumentMethod.set(true); 
    } 

    System.out.println("Method ID: " + methodID); 

    inInstrumentMethod.set(false); 
} 

我的猜测是,依赖没有被正确解析,并java.lang.ThreadLocal未加载(因而无法找到)。那么问题是,如何强制Java加载java.lang.ThreadLocal?在这种情况下,我认为我不能使用DefineClass;有没有其他选择?

+0

你得到'NoClassDefFoundError'为什么类? – EJP

我不认为有解决标准类java.lang.ThreadLocal的问题,而是与内部类扩展它,通过

new ThreadLocal<Boolean>() { 
    @Override protected Boolean initialValue() { 
     return Boolean.FALSE; 
    } 
}; 

通过DefineClass解决这个产生的的确可能因循环是不可能的内部类和外部类之间的依赖关系,所以没有允许定义它们的顺序,除非你有一个完整的ClassLoader,它可以按需返回类。

最简单的办法是避免内部类在所有的产生,这是可能的与Java 8:

private static ThreadLocal<Boolean> inInstrumentMethod 
            = ThreadLocal.withInitial(() -> Boolean.FALSE); 

如果使用之前的Java 8版本,你不能用它那方式,所以在这种情况下,最好的解决办法,就是重写代码接受null默认值作为初始值,无需指定不同的初始值:

private static ThreadLocal<Boolean> inInstrumentMethod = new ThreadLocal<>(); 

public static void onEntry(int methodID) 
{ 
    if (inInstrumentMethod.get()!=null) { 
     return; 
    } else { 
     inInstrumentMethod.set(true); 
    } 

    System.out.println("Method ID: " + methodID); 

    inInstrumentMethod.set(null); 
} 

你也可以转换的是匿名内部班级到顶级班。从那以后,这个类对先前的外部类没有依赖性,在定义使用它的类之前首先定义该子类ThreadLocal应该解决问题。

+0

谢谢。你完全正确!我让内部类成为适当的类,它工作得很好。 – xuq01