很早计划写篇研究JVM类加载源码的,忙于项目一直没时间深入研究,最近又要换工作,怕最近没时间研究了。之前一些粗浅的研究,主要是defineClass()和loadClass()方法在JVM源码中的几个相关位置,作个简单记录。
1.defineClass
由字节码加载自定义类,最终归结于java.lang.ClassLoader. defineClass0()这个native方法(关于java系统类层面的类加载机制,参见之前的两篇文章,本文只涉及JVM的c/c++层面源码)。
该方法通过jni实现,对应的c代码位于:
%openjdk-home%\jdk\src\share\native\java\lang\classload.c
实现该方法的几层主要调用如下:
Java_java_lang_ClassLoader_defineClass1();
→JVM_DefineClassWithSource();
→jvm_define_class_common();
→SystemDictionary::resolve_from_stream();
%openjdk-home%\hotspot\src\share\vm\prims\jvm.cpp
最后一步用到的SystemDictionary这个类位于
%openjdk-home%\hotspot\src\share\vm\classfile\systemDictionary.cpp
SystemDictionary::resolve_from_stream()这个方法中,命名空间过滤部分源码如下:
const char* pkg = "java/";
if (!HAS_PENDING_EXCEPTION &&
!class_loader.is_null() &&
!parsed_name.is_null() &&
!strncmp((const char*)parsed_name->bytes(), pkg, strlen(pkg))) {
// It is illegal to define classes in the "java." package from
// JVM_DefineClass or jni_DefineClass unless you're the bootclassloader
ResourceMark rm(THREAD);
char* name = parsed_name->as_C_string();
char* index = strrchr(name, '/');
*index = '\0'; // chop to just the package name
while ((index = strchr(name, '/')) != NULL) {
*index = '.'; // replace '/' with '.' in package name
}
const char* fmt = "Prohibited package name: %s";
size_t len = strlen(fmt) + strlen(name);
char* message = NEW_RESOURCE_ARRAY(char, len);
jio_snprintf(message, len, fmt, name);
Exceptions::_throw_msg(THREAD_AND_LOCATION,
vmSymbols::java_lang_SecurityException(), message);
}
高亮的几行代码可以看出:如类名以java.开头,将抛出java.lang.SecurityException异常。之前。之前尝试用自定义的方式加载系统类时,发生异常,根源就在这里。
理论上,删除或修改这段代码,就可以实现自定义系统类加载。不过编译JVM本身就是比较复杂的工作,至今尚未实现过~~~
2.loadClass
那么以java.开头java系统类是如何实现加载的?其流程与上面分析的基本类似。这里不再详细叙述,只给出几个关键的方法:
(native方法) java.lang.Classload.findBootstrapClass()
→(classload.c) Java_java_lang_ClassLoader_findBootstrapClass
→(jvm.cpp) find_class_from_class_loader()
→(systemDictionary.cpp) resolve_instance_class_or_null()
→(java.lang.Classload.class)checkPackageAccess
→(java.lang.SecurityManager.class)checkPackageAccess
与之前有所不同的是安全检查是通过JNI反调java方法实现的
作者:编程趋势
出处:http://www.cnblogs.com/codetrend/
作者微博:http://weibo.com/liuxue9527
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。