让我们一起跟随ClassLoader里的本地方法 findBootstrapClass(), 进入jvm执行启动类加载器加载类的内部实现。
java 代码
1.private Class findBootstrapClass0(String name)
2. throws ClassNotFoundException
3. {
4. check();
5. if (!checkName(name))
6. throw new ClassNotFoundException(name);
7. return findBootstrapClass(name);
8. }
9.
10. private native Class findBootstrapClass(String name)
11. throws ClassNotFoundException;
cpp 代码
1.// 摘自 j2se\src\share\classes\java\lang\ClassLoader.c
2.// 表示该函数将被 java class 以jni方式调用
3.JNIEXPORT jclass JNICALL
4.Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader,
5.jstring classname)
6.{
7. char *clname;
8. jclass cls = 0;
9. char buf[128];
10.
11. if (classname == NULL) {
12. // 类名不能为空
13. JNU_ThrowClassNotFoundException(env, 0);
14. return 0;
15. }
16.
17. // 将java的string转成unicode字符, 如果unicode字符长度不超过128
18. // 则不分配内存,直接拿buf缓存来使用
19. // 否则就malloc一块内存存放, 如果malloc失败, 则返回NULL
20. clname = getUTF(env, classname, buf, sizeof(buf));
21. if (clname == NULL) {
22. // 类名为空, 说明 JVM 内存分配失败, 抛出邪恶的OOM.
23. JNU_ThrowOutOfMemoryError(env, NULL);
24. return NULL;
25. }
26.
27. // 将 '.' 转换成 '/'
28. VerifyFixClassname(clname);
29.
30. if (!VerifyClassname(clname, JNI_TRUE)) {
31. // 如果指定的类名不合法, 抛出异常
32. JNU_ThrowClassNotFoundException(env, clname);
33. goto done;
34. }
35.
36. // 让jvm使用启动类加载器加载类, 第四位标志0表示使用启动类加载器,
37. // throwError为JNI_FALSE时抛出 ClassNotFoundException,而JNI_TRUE抛出NoClassDefFoundError
38. cls = JVM_FindClassFromClassLoader(env, clname, JNI_FALSE, 0, JNI_FALSE);
39.
40.done:
41. if (clname != buf) {
42. // 类名的格式有问题,且没有走buf缓存,则释放掉创建的内存, 防止内存泄漏
43. free(clname);
44. }
45.
46. return cls;
47.}
cpp 代码
1.// 摘自 hotspot\src\share\vm\prims\jvm.h
2./*
3.* jvm.h头文件, 类似java接口的定义。
4.× 根据给定的classLoader来加载指定类
5.×
6.× *env JNI运行环境
7.× *name 类名(路径)
8.× init 是否需要初始化类的内部数据结构
9.× loader 类加载器标识
10.× throwError 抛出的异常类型
11.*/
12.JNIEXPORT jclass JNICALL
13.JVM_FindClassFromClassLoader(JNIEnv *env, const char *name, jboolean init,
14.jobject loader, jboolean throwError);
cpp 代码
1.// 摘自 hotspot\src\share\vm\prims\jvm.cpp
2.JVM_ENTRY(jclass, JVM_FindClassFromClassLoader(JNIEnv* env, const char* name,
3. jboolean init, jobject loader,jboolean throwError))
4.
5.JVMWrapper3("JVM_FindClassFromClassLoader %s throw %s", name,
6.throwError ? "error" : "exception");
7.
8.// 确保字符串不为NULL且长度不大于 (1 << 16) -1 , 否则抛出异常
9.if (name == NULL || (int)strlen(name) > symbolOopDesc::max_length()) {
10. if (throwError) {
11. THROW_MSG_0(vmSymbols::java_lang_NoClassDefFoundError(), name);
12. } else {
13. THROW_MSG_0(vmSymbols::java_lang_ClassNotFoundException(), name);
14. }
15.}
16.
17.// 将类名放入一个hashmap, 标记符号用的, 并构造为 symbolHandle
18.// (注意: Handle是一种间接的, 由线程变量分配空间的类,作用是防止GC回收)
19.// CHECK_0是一个宏, 作用是判断是否有没有处理掉的异常, 如果有, 返回0
20.symbolHandle h_name = oopFactory::new_symbol_handle(name, CHECK_0);
21.
22.// 将classLoader标识转换成JVM内部表示的数据结构, 并构造为 Handle
23.Handle h_loader(THREAD, JNIHandles::resolve(loader));
24.
25.jclass result = find_class_from_class_loader(env, h_name, init, h_loader,
26.Handle(), throwError, thread);
27.
28.if (TraceClassResolution && result != NULL) {
29. trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result)));
30.}
31.
32.return result;
33.JVM_END
cpp 代码
1.// 摘自 hotspot\src\share\vm\prims\jvm.cpp
2.jclass find_class_from_class_loader(JNIEnv* env, symbolHandle name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS) {
3.
4.// 生成类的内部数据结构, 核心步骤,非常复杂, 后期补充一下这里, 但是对核心逻辑没影响
5.klassOop klass = SystemDictionary::resolve_or_fail(name, loader, protection_domain, throwError, CHECK_0);
6.
7.// 将类的数据结构, 构造为 KlassHandle
8.KlassHandle klass_handle(THREAD, klass);
9.
10.if (init && klass_handle->oop_is_instance()) {
11.// 初始化类内部的数据结构
12.klass_handle->initialize(CHECK_0);
13.}
14.
15.// 分配内存, 生成class对象
16.return (jclass) JNIHandles::make_local(env, klass_handle->java_mirror());
17.}
java 代码
1.private Class findBootstrapClass0(String name)
2. throws ClassNotFoundException
3. {
4. check();
5. if (!checkName(name))
6. throw new ClassNotFoundException(name);
7. return findBootstrapClass(name);
8. }
9.
10. private native Class findBootstrapClass(String name)
11. throws ClassNotFoundException;
cpp 代码
1.// 摘自 j2se\src\share\classes\java\lang\ClassLoader.c
2.// 表示该函数将被 java class 以jni方式调用
3.JNIEXPORT jclass JNICALL
4.Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader,
5.jstring classname)
6.{
7. char *clname;
8. jclass cls = 0;
9. char buf[128];
10.
11. if (classname == NULL) {
12. // 类名不能为空
13. JNU_ThrowClassNotFoundException(env, 0);
14. return 0;
15. }
16.
17. // 将java的string转成unicode字符, 如果unicode字符长度不超过128
18. // 则不分配内存,直接拿buf缓存来使用
19. // 否则就malloc一块内存存放, 如果malloc失败, 则返回NULL
20. clname = getUTF(env, classname, buf, sizeof(buf));
21. if (clname == NULL) {
22. // 类名为空, 说明 JVM 内存分配失败, 抛出邪恶的OOM.
23. JNU_ThrowOutOfMemoryError(env, NULL);
24. return NULL;
25. }
26.
27. // 将 '.' 转换成 '/'
28. VerifyFixClassname(clname);
29.
30. if (!VerifyClassname(clname, JNI_TRUE)) {
31. // 如果指定的类名不合法, 抛出异常
32. JNU_ThrowClassNotFoundException(env, clname);
33. goto done;
34. }
35.
36. // 让jvm使用启动类加载器加载类, 第四位标志0表示使用启动类加载器,
37. // throwError为JNI_FALSE时抛出 ClassNotFoundException,而JNI_TRUE抛出NoClassDefFoundError
38. cls = JVM_FindClassFromClassLoader(env, clname, JNI_FALSE, 0, JNI_FALSE);
39.
40.done:
41. if (clname != buf) {
42. // 类名的格式有问题,且没有走buf缓存,则释放掉创建的内存, 防止内存泄漏
43. free(clname);
44. }
45.
46. return cls;
47.}
cpp 代码
1.// 摘自 hotspot\src\share\vm\prims\jvm.h
2./*
3.* jvm.h头文件, 类似java接口的定义。
4.× 根据给定的classLoader来加载指定类
5.×
6.× *env JNI运行环境
7.× *name 类名(路径)
8.× init 是否需要初始化类的内部数据结构
9.× loader 类加载器标识
10.× throwError 抛出的异常类型
11.*/
12.JNIEXPORT jclass JNICALL
13.JVM_FindClassFromClassLoader(JNIEnv *env, const char *name, jboolean init,
14.jobject loader, jboolean throwError);
cpp 代码
1.// 摘自 hotspot\src\share\vm\prims\jvm.cpp
2.JVM_ENTRY(jclass, JVM_FindClassFromClassLoader(JNIEnv* env, const char* name,
3. jboolean init, jobject loader,jboolean throwError))
4.
5.JVMWrapper3("JVM_FindClassFromClassLoader %s throw %s", name,
6.throwError ? "error" : "exception");
7.
8.// 确保字符串不为NULL且长度不大于 (1 << 16) -1 , 否则抛出异常
9.if (name == NULL || (int)strlen(name) > symbolOopDesc::max_length()) {
10. if (throwError) {
11. THROW_MSG_0(vmSymbols::java_lang_NoClassDefFoundError(), name);
12. } else {
13. THROW_MSG_0(vmSymbols::java_lang_ClassNotFoundException(), name);
14. }
15.}
16.
17.// 将类名放入一个hashmap, 标记符号用的, 并构造为 symbolHandle
18.// (注意: Handle是一种间接的, 由线程变量分配空间的类,作用是防止GC回收)
19.// CHECK_0是一个宏, 作用是判断是否有没有处理掉的异常, 如果有, 返回0
20.symbolHandle h_name = oopFactory::new_symbol_handle(name, CHECK_0);
21.
22.// 将classLoader标识转换成JVM内部表示的数据结构, 并构造为 Handle
23.Handle h_loader(THREAD, JNIHandles::resolve(loader));
24.
25.jclass result = find_class_from_class_loader(env, h_name, init, h_loader,
26.Handle(), throwError, thread);
27.
28.if (TraceClassResolution && result != NULL) {
29. trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result)));
30.}
31.
32.return result;
33.JVM_END
cpp 代码
1.// 摘自 hotspot\src\share\vm\prims\jvm.cpp
2.jclass find_class_from_class_loader(JNIEnv* env, symbolHandle name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS) {
3.
4.// 生成类的内部数据结构, 核心步骤,非常复杂, 后期补充一下这里, 但是对核心逻辑没影响
5.klassOop klass = SystemDictionary::resolve_or_fail(name, loader, protection_domain, throwError, CHECK_0);
6.
7.// 将类的数据结构, 构造为 KlassHandle
8.KlassHandle klass_handle(THREAD, klass);
9.
10.if (init && klass_handle->oop_is_instance()) {
11.// 初始化类内部的数据结构
12.klass_handle->initialize(CHECK_0);
13.}
14.
15.// 分配内存, 生成class对象
16.return (jclass) JNIHandles::make_local(env, klass_handle->java_mirror());
17.}