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

如何获取一个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和.dll,通过System.load()加载对应本地链接库,最后调用InstancesOfClass.getInstances(Class<?> targetClass) 方法即可。

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

雷军公布小米澎湃 OS 完整系统架构,称底层全部重构 语雀 10 月 23 日故障原因及修复过程公告 微软 CEO 纳德拉:放弃 Windows Phone 和移动业务是错误决策 Java 11 和 Java 17 使用率均超 Java 8 Hugging Face 被限制访问 语雀网络故障持续大约 10 小时,现已恢复正常 国家数据局正式揭牌 Oracle 推出 Visual Studio Code 的 Java 开发扩展 马斯克:如果维基百科改名“维鸡百科”就捐款 10 亿美元 MySQL 8.2.0 GA
{{o.name}}
{{m.name}}

猜你喜欢

转载自my.oschina.net/u/3276866/blog/10123262