默认题主对JVM的类加载机制了解不是很深入,VM Classloader、ExtClassLoader、AppClassLoader、AppletClassLoader以及自定义类加载器的作用,以及双亲委派机制等基本知识请自行baidu,很多技术博客对此都有诠释,在此不再赘述。
其中ExtClassLoader和AppClassLoader都是Java实现的,VM ClassLoader作为HotSpot VM实现的一部分使用C++实现,不管是ExtClassLoader,抑或AppClassLoader,还是其他在VM ClassLoader管辖的class文件都会一视同仁地通过Bootstrap ClassLoader加载,需要说明的是VM ClassLoader是一个顶级加载器,意味着它是没有父加载器的。
具体到题主问的问题,就HotSpot VM而言,上述的加载过程实现的很明确,可以直接贴代码了:
instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) {
ResourceMark rm(THREAD);
EventMark m("loading class %s", h_name->as_C_string());
ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion);
stringStream st;
// st.print() uses too much stack space while handling a StackOverflowError // st.print("%s.class", h_name->as_utf8()); st.print_raw(h_name->as_utf8());
st.print_raw(".class");
char* name = st.as_string();
// Lookup stream for parsing .class file ClassFileStream* stream = NULL;
int classpath_index = 0;
{
PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(),
((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(),
PerfClassTraceTime::CLASS_LOAD);
ClassPathEntry* e = _first_entry;
while (e != NULL) {
stream = e->open_stream(name, CHECK_NULL);
if (stream != NULL) {
break;
}
e = e->next();
++classpath_index;
}
}
instanceKlassHandle h;
if (stream != NULL) {
// class file found, parse it ClassFileParser parser(stream);
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
Handle protection_domain;
TempNewSymbol parsed_name = NULL;
instanceKlassHandle result = parser.parseClassFile(h_name,
loader_data,
protection_domain,
parsed_name,
false,
CHECK_(h));
// add to package table if (add_package(name, classpath_index, THREAD)) {
h = result;
}
}
return h;
}
这个函数是这么被调用的:
instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
instanceKlassHandle nh = instanceKlassHandle(); // null Handle
if (class_loader.is_null()) {
// Search the shared system dictionary for classes preloaded into the
// shared spaces.
instanceKlassHandle k;
{
PerfTraceTime vmtimer(ClassLoader::perf_shared_classload_time());
k = load_shared_class(class_name, class_loader, THREAD);
}
if (k.is_null()) {
// Use VM class loader
PerfTraceTime vmtimer(ClassLoader::perf_sys_classload_time());
k = ClassLoader::load_classfile(class_name, CHECK_(nh));
}
// find_or_define_instance_class may return a different InstanceKlass
if (!k.is_null()) {
k = find_or_define_instance_class(class_name, class_loader, k, CHECK_(nh));
}
return k;
} else {
// Use user specified class loader to load class. Call loadClass operation on class_loader.
ResourceMark rm(THREAD);
assert(THREAD->is_Java_thread(), "must be a JavaThread");
JavaThread* jt = (JavaThread*) THREAD;
PerfClassTraceTime vmtimer(ClassLoader::perf_app_classload_time(),
ClassLoader::perf_app_classload_selftime(),
ClassLoader::perf_app_classload_count(),
jt->get_thread_stat()->perf_recursion_counts_addr(),
jt->get_thread_stat()->perf_timers_addr(),
PerfClassTraceTime::CLASS_LOAD);
Handle s = java_lang_String::create_from_symbol(class_name, CHECK_(nh));
// Translate to external class name format, i.e., convert '/' chars to '.'
Handle string = java_lang_String::externalize_classname(s, CHECK_(nh));
JavaValue result(T_OBJECT);
KlassHandle spec_klass (THREAD, SystemDictionary::ClassLoader_klass());
// Call public unsynchronized loadClass(String) directly for all class loaders
// for parallelCapable class loaders. JDK >=7, loadClass(String, boolean) will
// acquire a class-name based lock rather than the class loader object lock.
// JDK < 7 already acquire the class loader lock in loadClass(String, boolean),
// so the call to loadClassInternal() was not required.
//
// UnsyncloadClass flag means both call loadClass(String) and do
// not acquire the class loader lock even for class loaders that are
// not parallelCapable. This was a risky transitional
// flag for diagnostic purposes only. It is risky to call
// custom class loaders without synchronization.
// WARNING If a custom class loader does NOT synchronizer findClass, or callers of
// findClass, the UnsyncloadClass flag risks unexpected timing bugs in the field.
// Do NOT assume this will be supported in future releases.
//
// Added MustCallLoadClassInternal in case we discover in the field
// a customer that counts on this call
if (MustCallLoadClassInternal && has_loadClassInternal()) {
JavaCalls::call_special(&result,
class_loader,
spec_klass,
vmSymbols::loadClassInternal_name(),
vmSymbols::string_class_signature(),
string,
CHECK_(nh));
} else {
JavaCalls::call_virtual(&result,
class_loader,
spec_klass,
vmSymbols::loadClass_name(),
vmSymbols::string_class_signature(),
string,
CHECK_(nh));
}
assert(result.get_type() == T_OBJECT, "just checking");
oop obj = (oop) result.get_jobject();
// Primitive classes return null since forName() can not be
// used to obtain any of the Class objects representing primitives or void
if ((obj != NULL) && !(java_lang_Class::is_primitive(obj))) {
instanceKlassHandle k =
instanceKlassHandle(THREAD, java_lang_Class::as_Klass(obj));
// For user defined Java class loaders, check that the name returned is
// the same as that requested. This check is done for the bootstrap
// loader when parsing the class file.
if (class_name == k->name()) {
return k;
}
}
// Class is not found or has the wrong name, return NULL
return nh;
}
}
这里可以看到根据参数class_loader句柄是否为null,采用了不同的加载机制~