Class的forName的demo
我们平时写代码时可以通过Class.forName传入三个参数类全限定名称.就可以返回Class对象.那么加载类是如何实现的呢?
Class.forName的调用流程
- 实现通过Reflection获取调用forName的类,然后直接调用forName0方法进行加载。传入四个参数: 类全名、是否初始化、调用者class的classloader、调用者类.
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
forName0这个方法是native方法调用,那么接下
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
Class#forName0的JVM层的实现
JVM虚拟机中Class.c中Java_java_lang_Class_forName0,这就是Java中forName0的native方法调用所对应的JVM层方法, 这里可以看到第一个参数是JNIEnv,第二个参数是当前类,第三个参数是的类全限定名,第四个参数是是否初始化,第五个参数是加载的classloader实例,第六个参数是调用者的的class。
- 下面代码省略了部分代码,保留了主要逻辑,其函数主要调用JVM_FindClassFromCaller查找类全名的class.
JNIEXPORT jclass JNICALL
Java_java_lang_Class_forName0(JNIEnv *env, jclass this, jstring classname,jboolean initialize, jobject loader, jclass caller)
{
char *clname;
jclass cls = 0;
//省略
cls = JVM_FindClassFromCaller(env, clname, initialize, loader, caller);
//省略
return cls;
}
Class#JVM_FindClassFromCaller
- 使用传入的classloader去加载这个类全名的Class,并使用调用的class的protection domain。
- find_class_from_class_loader从当前的classloader加载class。
JVM_ENTRY(jclass, JVM_FindClassFromCaller(JNIEnv* env, const char* name,jboolean init, jobject loader,jclass caller))
//省略部分代码
Handle h_loader(THREAD, loader_oop);
Handle h_prot(THREAD, protection_domain);
jclass result = find_class_from_class_loader(env, h_name, init, h_loader,h_prot, false, THREAD);
if (log_is_enabled(Debug, class, resolve) && result != NULL) {trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result)));
}
return result;
JVM_END
Class#find_class_from_class_loader
- 调用SystemDictionary的resolve_or_fail查询并解析字节码,加载虚拟机中成为Class对象.
- 检查是否需要初始化Class的初始化.
jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init, Handle loader, Handle protection_domain,
jboolean throwError, TRAPS) {
//省略部分代码
Klass* klass = SystemDictionary::resolve_or_fail(name, loader, protection_domain, throwError != 0, CHECK_NULL);
// Check if we should initialize the class
if (init && klass->is_instance_klass()) {
klass->initialize(CHECK_NULL);
}
return (jclass) JNIHandles::make_local(THREAD, klass->java_mirror());
}
SystemDictionary#resolve_or_fail
- 调用resolve_or_null即系class_name所对应的字节码为Klass,并检查异常.
Klass* SystemDictionary::resolve_or_fail(Symbol* class_name, Handle class_loader, Handle protection_domain, bool throw_error, TRAPS) {
Klass* klass = resolve_or_null(class_name, class_loader, protection_domain, THREAD);
// Check for pending exception or null klass, and throw exception
if (HAS_PENDING_EXCEPTION || klass == NULL) {
handle_resolution_exception(class_name, throw_error, CHECK_NULL);
}
return klass;
}
SystemDictionary#resolve_or_null
- 判断是数组调用resolve_array_class_or_null, 对象则调用resolve_instance_class_or_null_helper
Klass* SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) {
if (Signature::is_array(class_name)) {
return resolve_array_class_or_null(class_name, class_loader, protection_domain, THREAD);
} else {
return resolve_instance_class_or_null_helper(class_name, class_loader, protection_domain, THREAD);
}
SystemDictionary#resolve_instance_class_or_null_helper
- 如果是对象类型则忽略类全名中L和;字符,然后调用resolve_instance_class_or_null继续解析.
SystemDictionary::resolve_instance_class_or_null_helper(Symbol* class_name, Handle class_loader,Handle protection_domain, TRAPS) {
assert(class_name != NULL && !Signature::is_array(class_name), "must be");
if (Signature::has_envelope(class_name)) {
ResourceMark rm(THREAD);
// Ignore wrapping L and ;.
TempNewSymbol name = SymbolTable::new_symbol(class_name->as_C_string() + 1, class_name->utf8_length() - 2);
return resolve_instance_class_or_null(name, class_loader, protection_domain, THREAD);
} else {
return resolve_instance_class_or_null(class_name, class_loader, protection_domain, THREAD);
}
}
SystemDictionary#resolve_instance_class_or_null
- 获取ClassLoaderData的Dictionary,就算类全名的hash值
- 如果Dictionary没有查询到类的实例,则获取Classloader的ObjectLocker锁.
- 然后获取MutexLocker锁. 再从dictionary中调用find_class传入类的全名的hash值以及类全名,如果已经加载,则赋值loaded_class。
- 获取PlaceholderEntry,继续处理加载父类。
- 如果loaded_class为空,则调用load_instance_class加载类实例。
SystemDictionary::resolve_instance_class_or_null(Symbol* name,Handle class_loader,Handle protection_domain,TRAPS) {
assert(name != NULL && !Signature::is_array(name) &&
!Signature::has_envelope(name), "invalid class name");
EventClassLoad class_load_start_event;
HandleMark hm(THREAD);
class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
ClassLoaderData* loader_data = register_loader(class_loader);
Dictionary* dictionary = loader_data->dictionary();
unsigned int name_hash = dictionary->compute_hash(name);
InstanceKlass* probe = dictionary->find(name_hash, name, protection_domain);
if (probe != NULL) return probe;
Handle lockObject = get_loader_lock_or_null(class_loader);
ObjectLocker ol(lockObject, THREAD);
bool super_load_in_progress = false;
InstanceKlass* loaded_class = NULL;
Symbol* superclassname = NULL;
assert(THREAD->can_call_java(),
"can not load classes with compiler thread: class=%s, classloader=%s",
name->as_C_string(),
class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string());
assert(placeholders()->compute_hash(name) == name_hash, "they're the same hashcode");
// Check again (after locking) if the class already exists in SystemDictionary
{
MutexLocker mu(THREAD, SystemDictionary_lock);
InstanceKlass* check = dictionary->find_class(name_hash, name);
if (check != NULL) {
// InstanceKlass is already loaded, but we still need to check protection domain below.
loaded_class = check;
} else {
PlaceholderEntry* placeholder = placeholders()->get_entry(name_hash, name, loader_data);
if (placeholder != NULL && placeholder->super_load_in_progress()) {
super_load_in_progress = true;
superclassname = placeholder->supername();
assert(superclassname != NULL, "superclass has to have a name");
}
}
}
// If the class is in the placeholder table with super_class set,
// handle superclass loading in progress.
if (super_load_in_progress) {
handle_parallel_super_load(name, superclassname,
class_loader,
protection_domain,
CHECK_NULL);
}
bool throw_circularity_error = false;
if (loaded_class == NULL) {
bool load_placeholder_added = false;.
// case 4. traditional class loaders that break the classloader object lock
// as a legacy deadlock workaround. Detection of this case requires that
// this check is done while holding the classloader object lock,
// and that lock is still held when calling classloader's loadClass.
// For these classloaders, we ensure that the first requestor
// completes the load and other requestors wait for completion.
{
MutexLocker mu(THREAD, SystemDictionary_lock);
if (should_wait_for_loading(class_loader)) {
loaded_class = handle_parallel_loading(THREAD,
name_hash,
name,
loader_data,
lockObject, &throw_circularity_error);
}
// Recheck if the class has been loaded for all class loader cases and
// add a LOAD_INSTANCE placeholder while holding the SystemDictionary_lock.
if (!throw_circularity_error && loaded_class == NULL) {
InstanceKlass* check = dictionary->find_class(name_hash, name);
if (check != NULL) {
loaded_class = check;
} else if (should_wait_for_loading(class_loader)) {
// Add the LOAD_INSTANCE token. Threads will wait on loading to complete for this thread.
PlaceholderEntry* newprobe = placeholders()->find_and_add(name_hash, name, loader_data, PlaceholderTable::LOAD_INSTANCE,NULL,THREAD);
load_placeholder_added = true;
}
}
}
// Must throw error outside of owning lock
if (throw_circularity_error) {
assert(!HAS_PENDING_EXCEPTION && !load_placeholder_added, "circularity error cleanup");
ResourceMark rm(THREAD);
THROW_MSG_NULL(vmSymbols::java_lang_ClassCircularityError(), name->as_C_string());
}
// Be careful when modifying this code: once you have run
// placeholders()->find_and_add(PlaceholderTable::LOAD_INSTANCE),
// you need to find_and_remove it before returning.
// So be careful to not exit with a CHECK_ macro between these calls.
if (loaded_class == NULL) {
// Do actual loading
loaded_class = load_instance_class(name_hash, name, class_loader, THREAD);
}
if (load_placeholder_added) {
// clean up placeholder entries for LOAD_INSTANCE success or error
// This brackets the SystemDictionary updates for both defining
// and initiating loaders
MutexLocker mu(THREAD, SystemDictionary_lock);
placeholders()->find_and_remove(name_hash, name, loader_data, PlaceholderTable::LOAD_INSTANCE, THREAD);
SystemDictionary_lock->notify_all();
}
}
if (HAS_PENDING_EXCEPTION || loaded_class == NULL) {
return NULL;
}
if (class_load_start_event.should_commit()) {
post_class_load_event(&class_load_start_event, loaded_class, loader_data);
}
// Make sure we have the right class in the dictionary
DEBUG_ONLY(verify_dictionary_entry(name, loaded_class));
// Check if the protection domain is present it has the right access
if (protection_domain() != NULL) {
// Verify protection domain. If it fails an exception is thrown
dictionary->validate_protection_domain(name_hash, loaded_class, class_loader, protection_domain, CHECK_NULL);
}
return loaded_class;
}
SystemDictionary#load_instance_class
- 调用load_instance_class_impl去加载Class对象.
- 记录class到classloader的ClassLoaderData对象中.并更新SystemDictionary。
- post_class_load就是类加载的后置处理(调用JVMTIExport接口,这是java开发者暴露的接口调用)
InstanceKlass* SystemDictionary::load_instance_class(unsigned int name_hash, Symbol* name, Handle class_loader,TRAPS) {
InstanceKlass* loaded_class = load_instance_class_impl(name, class_loader, CHECK_NULL);
// If everything was OK (no exceptions, no null return value), and
// class_loader is NOT the defining loader, do a little more bookkeeping.
if (loaded_class != NULL &&
loaded_class->class_loader() != class_loader()) {
check_constraints(name_hash, loaded_class, class_loader, false, CHECK_NULL);
// Record dependency for non-parent delegation.
// This recording keeps the defining class loader of the klass (loaded_class) found
// from being unloaded while the initiating class loader is loaded
// even if the reference to the defining class loader is dropped
// before references to the initiating class loader.
ClassLoaderData* loader_data = class_loader_data(class_loader);
loader_data->record_dependency(loaded_class);
{ // Grabbing the Compile_lock prevents systemDictionary updates
// during compilations.
MutexLocker mu(THREAD, Compile_lock);
update_dictionary(name_hash, loaded_class, class_loader);
}
if (JvmtiExport::should_post_class_load()) {
JvmtiExport::post_class_load(THREAD, loaded_class);
}
}
return loaded_class;
}
SystemDictionary#load_instance_class_impl
- 如果classloader为空,则利用vm的bootstrap classloader的加载类.
- 如果classloader不为空,则通过JavaCalls::call_virtual调用用户定义的classloader的loadClass方法去加载类。
InstanceKlass* SystemDictionary::load_instance_class_impl(Symbol* class_name, Handle class_loader, TRAPS) {
if (class_loader.is_null()) {
ResourceMark rm(THREAD);
PackageEntry* pkg_entry = NULL;
bool search_only_bootloader_append = false;
ClassLoaderData *loader_data = class_loader_data(class_loader);
//省略代码
// Search for classes in the CDS archive.
InstanceKlass* k = NULL;
#if INCLUDE_CDS
if (UseSharedSpaces)
{
InstanceKlass* ik = SystemDictionaryShared::find_builtin_class(class_name);
if (ik != NULL && ik->is_shared_boot_class() && !ik->shared_loading_failed()) {
SharedClassLoadingMark slm(THREAD, ik);
k = load_shared_class(ik, class_loader, Handle(), NULL, pkg_entry, CHECK_NULL);
}
}
#endif
if (k == NULL) {
// Use VM class loader
PerfTraceTime vmtimer(ClassLoader::perf_sys_classload_time());
k = ClassLoader::load_class(class_name, search_only_bootloader_append, CHECK_NULL);
}
// find_or_define_instance_class may return a different InstanceKlass
if (k != NULL) {
CDS_ONLY(SharedClassLoadingMark slm(THREAD, k);)
k = find_or_define_instance_class(class_name, class_loader, k, CHECK_NULL);
}
return k;
} else {
// Use user specified class loader to load class. Call loadClass operation on class_loader.
ResourceMark rm(THREAD);
JavaThread* jt = THREAD;
// Translate to external class name format, i.e., convert '/' chars to '.'
Handle string = java_lang_String::externalize_classname(class_name, CHECK_NULL);
JavaValue result(T_OBJECT);
InstanceKlass* spec_klass = vmClasses::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).
JavaCalls::call_virtual(&result,
class_loader,
spec_klass,
vmSymbols::loadClass_name(),
vmSymbols::string_class_signature(),
string,
CHECK_NULL);
assert(result.get_type() == T_OBJECT, "just checking");
oop obj = result.get_oop();
// 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))) {
InstanceKlass* k = InstanceKlass::cast(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 NULL;
}
}
总结
今天主要是对Class.forName底层实现的分析。
- 通过计算类全名的hash值和类全名底层的loader所对应的SystemDictionary的查询类是否已经加载。
- 如果没有查询到,判断是否存在classloader,来决定是bootstrap classloader还是JavaCalls#call调用自定义的classloader的loadClass去加载类。