很早计划写篇研究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方法实现的

posted on 2013-04-02 14:40  编程趋势  阅读(1290)  评论(0编辑  收藏  举报