您的位置:  首页 > 技术杂谈 > 正文

如何获取一个类的对象实例

2023-10-26 14:00 https://my.oschina.net/u/3276866/blog/10123262 抽刀断水-鹰影 次阅读 条评论

如何获取一个Java类的对象实例呢?这个类即不是单例,也没有在代码里保存所有对象,也不一定由Spring管理,甚至还不能修改其源码的情况下,我们该怎么获取这个类的所有对象实例呢?这里介绍一种基于JVMTI的实现方法。

使用说明

首先引用maven依赖

<dependency>
   <groupId>io.github.liubsyy</groupId>
  <artifactId>FindInstancesOfClass</artifactId>
   <version>1.0.1</version>
</dependency>

然后直接调用函数 InstancesOfClass.getInstances(Class<?> targetClass) 即可获取一个类的所有对象实例

public class InstancesOfClass {
    /**
     * native方法 : 返回所有的实例对象
     * @param targetClass 需要查询实例的Class
     * @return
     */
    public static native Object[] getInstances(Class<?> targetClass);
}

实现原理

Java里面是没有根据类获取实例的接口的,需要用到JVMTI的接口 IterateOverInstancesOfClass和GetObjectsWithTags

首先写一个包含native方法的类

public class InstancesOfClass {
    /**
     * native方法 : 返回所有的实例对象
     * @param targetClass 需要查询实例的Class
     * @return
     */
    public static native Object[] getInstances(Class<?> targetClass);
}

再用javah生成.h文件,然后用C++写实现部分

#include <jni.h>
#include <jvmti.h>
#include "com_liubs_findinstances_jvmti_InstancesOfClass.h"


static jvmtiIterationControl JNICALL objectInstanceCallback(jlong class_tag, jlong size, jlong* tag_ptr, void* user_data) {
    *tag_ptr = 1;
    return JVMTI_ITERATION_CONTINUE;
}

JNIEXPORT jobjectArray JNICALL Java_com_liubs_findinstances_jvmti_InstancesOfClass_getInstances(JNIEnv* env, jclass clazz, jclass targetClazz) {
    JavaVM* vm;
    env->GetJavaVM(&vm);

    jvmtiEnv* jvmti;
    vm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_0);

    jvmtiCapabilities capabilities = {0};
    capabilities.can_tag_objects = 1;
    jvmti->AddCapabilities(&capabilities);

    jvmti->IterateOverInstancesOfClass(targetClazz, JVMTI_HEAP_OBJECT_EITHER,
                                       objectInstanceCallback, NULL);

    jlong tag = 1;
    jint count;
    jobject* instances;
    jvmti->GetObjectsWithTags(1, &tag, &count, &instances, NULL);

    printf("Found %d objects with tag\n", count);

    // 转换jobject* 为 jobjectArray 并返回
    jobjectArray result = env->NewObjectArray(count, targetClazz, NULL);
    for (int i = 0; i < count; i++) {
        env->SetObjectArrayElement(result, i, instances[i]);
    }

    jvmti->Deallocate((unsigned char*)instances);
    return result;
}

 

然后用gcc/g++编译cpp源码,生成linux/mac/windows下对应的动态链接库文件 .so, .dylib和findins.dll,通过System.load()加载对应本地链接库,最后调用InstancesOfClass.getInstances(Class<?> targetClass) 方法即可。

具体源码详见 https://github.com/Liubsyy/FindInstancesOfClass,里面包含了测试用例

 

 

 

 

展开阅读全文
  • 0
    感动
  • 0
    路过
  • 0
    高兴
  • 0
    难过
  • 0
    搞笑
  • 0
    无聊
  • 0
    愤怒
  • 0
    同情
热度排行
友情链接