代码之家  ›  专栏  ›  技术社区  ›  xuq01

解析JNI DefineClass中的依赖项

  •  1
  • xuq01  · 技术社区  · 7 年前

    我正在使用JVMTI编写一个应用程序。我试图检测字节码:通过在每个方法条目上注入方法调用。

    Proxy ,我使用JNI函数DefineClass加载它。我的 在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;
    }
    

    仪器方法 ,我得到一个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 在这种情况下;有其他选择吗?

    1 回复  |  直到 7 年前
        1
  •  1
  •   Holger    7 年前

    java.lang.ThreadLocal ,而是使用扩展它的内部类,由

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

    通过解决此问题 DefineClass ClassLoader 这会根据需要返回类。

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

    如果您使用的是Java8之前的版本,那么您不能这样使用它,因此在这种情况下,最好的解决方案是重写代码以接受 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