引入:
上文中提到Agent如何利用环境指针访问VM的(Watch)功能,这里主要讲解如何去管理类的。
分类9:管理类
a.GetLoadedClasses. 获得虚拟机中所有被加载的类的数组。
jvmtiError
GetLoadedClasses(jvmtiEnv* env,
jint* class_count_ptr,
jclass** classes_ptr)
从返回值可以看出,class_count_ptr表示被加载的类的数量,classes_ptr表示类的数组列表。
注意,这里不包含内置类型对应的包装器类。比如说java.lang.Integer.TYPE就不包含在此列表中。
b.GetClassLoaderClasses.获取虚拟机中所有的Classloader所管理的类。
jvmtiError
GetClassLoaderClasses(jvmtiEnv* env,
jobject initiating_loader,
jint* class_count_ptr,
jclass** classes_ptr)
c.GetClassSignature.获取某类的签名
jvmtiError
GetClassSignature(jvmtiEnv* env,
jclass klass,
char** signature_ptr,
char** generic_ptr)
这里的签名是用的JNI类型签名方式,比如说java.util.List 的类签名是 "Ljava/util/List;" 而 int[] 的类签名是 "[I"。
d.GetClassStatus.获取类状态
jvmtiError
GetClassStatus(jvmtiEnv* env,
jclass klass,
jint* status_ptr)
类的有如下状态,分别用状态标志位来表示:
JVMTI_CLASS_STATUS_VERIFIED |
1 |
类的字节码已经被修改 |
JVMTI_CLASS_STATUS_PREPARED |
2 |
类准备状态已经完成 |
JVMTI_CLASS_STATUS_INITIALIZED |
4 |
类初始化完毕,静态初始化块已运行 S |
JVMTI_CLASS_STATUS_ERROR |
8 |
类初始化错误,因此不可使用。 |
JVMTI_CLASS_STATUS_ARRAY |
16 |
类是个数组 |
JVMTI_CLASS_STATUS_PRIMITIVE |
32 |
类是个原子类(比如 java.lang.Integer.TYPE). |
e.GetSourceFileName.获取指定类的源代码文件名
jvmtiError
GetSourceFileName(jvmtiEnv* env,
jclass klass,
char** source_name_ptr)
f.GetClassModifiers.获取类的访问修饰符
jvmtiError
GetClassModifiers(jvmtiEnv* env,
jclass klass,
jint* modifiers_ptr)
一般类的访问修饰符就是 public/private/protected ,另外还有final.
另外,如果类是原子类(比如java.lang.Integer.TYPE),则它的访问修饰符必定是public final.并且一定没有对应的interface.
g.GetClassMethods.获取类的方法列表。
jvmtiError
GetClassMethods(jvmtiEnv* env,
jclass klass,
jint* method_count_ptr,
jmethodID** methods_ptr)
按照约定,分别返回方法数量以及方法的列表。注意,这个方法列表还包括构造器和静态初始块。
h.GetClassFields.获取类的字段列表。
jvmtiError
GetClassFields(jvmtiEnv* env,
jclass klass,
jint* field_count_ptr,
jfieldID** fields_ptr)
注意,这个字段列表只包含直接声明的字段,不包含它从父类中继承过来的字段。字段的返回顺序精确的等同于在类文件中声明的顺序。
i.GetImplementedInterfaces.获取类所实现的接口
jvmtiError
GetImplementedInterfaces(jvmtiEnv* env,
jclass klass,
jint* interface_count_ptr,
jclass** interfaces_ptr)
注意,对于类来说,这里只返回它直接implements XXX,XXX的接口。
对于接口来说,这里返回它 extends XXX的接口。
j.IsInterface.判断某类是否是一个接口
jvmtiError
IsInterface(jvmtiEnv* env,
jclass klass,
jboolean* is_interface_ptr)
k.IsArrayClass.判断某类是否是一个数组类
jvmtiError
IsArrayClass(jvmtiEnv* env,
jclass klass,
jboolean* is_array_class_ptr)
l.GetClassLoader.获取某类对应的类加载器的引用。
jvmtiError
GetClassLoader(jvmtiEnv* env,
jclass klass,
jobject* classloader_ptr)
m.GetSourceDebugExtension.获取类的debug扩展信息。
jvmtiError
GetSourceDebugExtension(jvmtiEnv* env,
jclass klass,
char** source_debug_extension_ptr)
n.RedefineClasses.重新定义一组类 (强大的热交换技术)
typedef struct {
jclass klass;
jint class_byte_count;
const unsigned char* class_bytes;
} jvmtiClassDefinition;
jvmtiError
RedefineClasses(jvmtiEnv* env,
jint class_count,
const jvmtiClassDefinition* class_definitions)
这功能挺有趣,因为如果指定的字节码,则重新定义某类。所以该方法通过传入一组字节码来重新定义一组类。重新定义某类之后,对于该类会有如下一些改变:
(1).线程无需被挂起。
(2).类中的所有断点都被清除。
(3).所有属性都被更新。(注意,这里的属性是class对象的属性,不是类文件中的属性,那个叫字段field)
(4).类的已有的所有实例,其在堆上的ID都不受影响,其含有的字段值都不受影响。
另外,对于类的重新定义,也有些约束:
(1)重定义可以改变方法体,常量池,字段。
(2)重定义不可以添加/修改/删除任何类中的方法和字段。
(3)重定义不可以修改方法签名,改变访问修饰符和继承关系。
本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/1587816,如需转载请自行联系原作者