典型的反射调用形式为:
private static void classForName() {
try {
// 获取 Class 对象
Class> clz = Class.forName("com.xx.xx.XX");
...
} catch (Exception e) {
e.printStackTrace();
}
}
1. Class.forName
public static Class> forName(String className)
throws ClassNotFoundException {
return forName(className, true, VMStack.getCallingClassLoader());
}
public static Class> forName(String name, boolean initialize,ClassLoader loader)
throws ClassNotFoundException{
if (loader == null) {
loader = BootClassLoader.getInstance();
}
Class> result;
try {
result = classForName(name, initialize, loader);
} catch (ClassNotFoundException e) {
Throwable cause = e.getCause();
if (cause instanceof LinkageError) {
throw (LinkageError) cause;
}
throw e;
}
return result;
}
static native Class> classForName(String className, boolean shouldInitialize,
ClassLoader classLoader) throws ClassNotFoundException;
Class.forName(String)
函数实际是封装调用另一个重载版本的Class.forName(String,boolean,ClassLoader)
, 在传入第三个参数时首先调用VMStack.getCallingClassLoader
方法,这个方法从函数名中大致可以判断出它的作用是获取当前调用者ClassLoader,最后再调用本地方法classForName
1.1 VMStack.getCallingClassLoader
native public static ClassLoader getCallingClassLoader();
// 定义在art/runtime/native/dalvik_system_VMStack.cc
static jobject VMStack_getCallingClassLoader(JNIEnv* env, jclass) {
ScopedFastNativeObjectAccess soa(env);
NthCallerVisitor visitor(soa.Self(), 2);
visitor.WalkStack();
if (UNLIKELY(visitor.caller == nullptr)) {
// The caller is an attached native thread.
return nullptr;
}
return soa.AddLocalReference(visitor.caller->GetDeclaringClass()->GetClassLoader());
}
这个方法的核心调用是visitor.WalkStack()
,WalkStack()的实现在art/runtime/stack.cc
,具体的实现这里先不深究(由于时间原因,这块内容还未理解透彻),不过从代码中可以大致看出WalkStack()方法是根据函数调用栈帧获取到当前调用者,继而获取对应的ClassLoader
2. Class_classForName
// "name" is in "binary name" format, e.g. "dalvik.system.Debug$1".
static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize,
jobject javaLoader) {
ScopedFastNativeObjectAccess soa(env);
ScopedUtfChars name(env, javaName);
if (name.c_str() == nullptr) {
return nullptr;
}
// 将com.xx.xx转换为com/xx/xx
if (!IsValidBinaryClassName(name.c_str())) {
soa.Self()->ThrowNewExceptionF("Ljava/lang/ClassNotFoundException;",
"Invalid name: %s", name.c_str());
return nullptr;
}
std::string descriptor(DotToDescriptor(name.c_str()));
StackHandleScope<2> hs(soa.Self());
Handle class_loader(hs.NewHandle(soa.Decode(javaLoader)));
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
//核心调用,调用ClassLinker::FindClass()
Handle c(
hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor.c_str(), class_loader)));
if (c.Get() == nullptr) {
ScopedLocalRef cause(env, env->ExceptionOccurred());
env->ExceptionClear();
jthrowable cnfe = reinterpret_cast(env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException,
WellKnownClasses::java_lang_ClassNotFoundException_init,
javaName, cause.get()));
if (cnfe != nullptr) {
// Make sure allocation didn't fail with an OOME.
env->Throw(cnfe);
}
return nullptr;
}
if (initialize) {
//确保类已经完成解析
class_linker->EnsureInitialized(soa.Self(), c, true, true);
}
return soa.AddLocalReference(c.Get());
}
从代码中可以看出核心调用是class_linker->FindClass(...)
3. ClassLinker::FindClass
mirror::Class* ClassLinker::FindClass(Thread* self,
const char* descriptor,
Handle class_loader) {
...
self->AssertNoPendingException();
if (descriptor[1] == '\0') {
// 只有基础类型的descriptor是1个字符
return FindPrimitiveClass(descriptor[0]);
}
const size_t hash = ComputeModifiedUtf8Hash(descriptor);
// 在传入的ClassLoader的已加载表中查找类, [3.1]
mirror::Class* klass = LookupClass(self, descriptor, hash, class_loader.Get());
if (klass != nullptr) {
//确保类已经被解析
return EnsureResolved(self, descriptor, klass);
}
// 执行到这里,意味着没有找到类
if (descriptor[0] == '[') {
return CreateArrayClass(self, descriptor, hash, class_loader);
} else if (class_loader.Get() == nullptr) {
// 如果ClassLoader是nullptr,则在boot_class_path_中查找
ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
if (pair.second != nullptr) {
return DefineClass(self,
descriptor,
hash,
ScopedNullHandle(),
*pair.first,
*pair.second);
} else {
//仍然没有找到的话,创建一个ClassNoDefFoundError
mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
self->SetException(pre_allocated);
return nullptr;
}
} else {
ScopedObjectAccessUnchecked soa(self);
mirror::Class* cp_klass;
//递归的在传入的ClassLoader以及它的各级parent中查找类, [3.2]
if (FindClassInPathClassLoader(soa, self, descriptor, hash, class_loader, &cp_klass)) {
if (cp_klass != nullptr) {
//找到,直接返回
return cp_klass;
}
}
//如果Runtime是编译器,则直接创建ClassNoDefFoundError,只有在dex2oat中创建的Runtime会是编译器
if (Runtime::Current()->IsAotCompiler()) {
mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
self->SetException(pre_allocated);
return nullptr;
}
//执行到意味着仍然没有找到相应的类
ScopedLocalRef class_loader_object(soa.Env(),
soa.AddLocalReference(class_loader.Get()));
std::string class_name_string(DescriptorToDot(descriptor));
ScopedLocalRef result(soa.Env(), nullptr);
{
ScopedThreadStateChange tsc(self, kNative);
ScopedLocalRef class_name_object(soa.Env(),
soa.Env()->NewStringUTF(class_name_string.c_str()));
if (class_name_object.get() == nullptr) {
return nullptr;
}
//调用ClassLoader的loadClass在传入的ClassLoader中查找
result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(),
WellKnownClasses::java_lang_ClassLoader_loadClass,
class_name_object.get()));
}
if (self->IsExceptionPending()) {
// If the ClassLoader threw, pass that exception up.
return nullptr;
} else if (result.get() == nullptr) {
// 抛出NullPointerException
ThrowNullPointerException(StringPrintf("ClassLoader.loadClass returned null for %s",
class_name_string.c_str()).c_str());
return nullptr;
} else {
// 终于找到
return soa.Decode(result.get());
}
}
UNREACHABLE();
}
ClassLinker::FindClass
的逻辑可以总结为:
- 如果要找的类是基础类型,则直接调用
FindPrimitiveClass
查找基础类型;如果不是则在传入的ClassLoader的已加载类表中查找类(首先会判断ClassLaoder是否为null,如果为null,就在boot_class_table_
中查找,否则就在ClassLoader自己的ClassTable
中查找),如果找到,确保类已经被解析并返回 - 如果在传入的ClassLoader的已加载类表中没有找到类,则首先判断ClassLoader是否为空,如果为空,在
boot_class_path_
中查找,如果不为空,则调用FindClassInPathClassLoader
在传入的ClassLoader以及它的各级parent中查找类 - 如果仍然没有找到,则调用传入的ClassLoader的
loadClass
在传入的ClassLoader中查找,找到返回,否则抛出异常
3.1 ClassLinker::LookupClass
mirror::Class* ClassLinker::LookupClass(Thread* self,
const char* descriptor,
size_t hash,
mirror::ClassLoader* class_loader) {
{
ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
//获取ClassLoader对应的ClassTable,如果ClassLoader为null,则则返回boot_class_table_
ClassTable* const class_table = ClassTableForClassLoader(class_loader);
if (class_table != nullptr) {
mirror::Class* result = class_table->Lookup(descriptor, hash);
if (result != nullptr) {
return result;
}
}
}
if (class_loader != nullptr || !dex_cache_boot_image_class_lookup_required_) {
return nullptr;
}
//在Image Space中查找类,Image Space映射的是boot.art和boot.oat
mirror::Class* result = LookupClassFromBootImage(descriptor);
if (result != nullptr) {
result = InsertClass(descriptor, result, hash);
} else {
constexpr uint32_t kMaxFailedDexCacheLookups = 1000;
if (++failed_dex_cache_class_lookups_ > kMaxFailedDexCacheLookups) {
AddBootImageClassesToClassTable();
}
}
return result;
}
ClassTable* ClassLinker::ClassTableForClassLoader(mirror::ClassLoader* class_loader) {
return class_loader == nullptr ? &boot_class_table_ : class_loader->GetClassTable();
}
3.2 ClassLinker::FindClassInPathClassLoader
bool ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
Thread* self,
const char* descriptor,
size_t hash,
Handle class_loader,
mirror::Class** result) {
//递归调用的终止条件
//如果是BootClassLoader,在boot_class_path_中查找类,并完成类的解析
if (IsBootClassLoader(soa, class_loader.Get())) {
ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
if (pair.second != nullptr) {
mirror::Class* klass = LookupClass(self, descriptor, hash, nullptr);
if (klass != nullptr) {
*result = EnsureResolved(self, descriptor, klass);
} else {
*result = DefineClass(self,descriptor,hash,
ScopedNullHandle(),
*pair.first,
*pair.second);
}
if (*result == nullptr) {
self->ClearException();
}
} else {
*result = nullptr;
}
return true;
}
//递归调用的终止条件
//确保传入的ClassLoader必须是PathClassLoader
if (class_loader->GetClass() != soa.Decode(
WellKnownClasses::dalvik_system_PathClassLoader)) {
*result = nullptr;
return false;
}
// Handles as RegisterDexFile may allocate dex caches (and cause thread suspension).
StackHandleScope<4> hs(self);
Handle h_parent(hs.NewHandle(class_loader->GetParent()));
//递归调用,在parent中查找,一般情况下,一个应用的PathClassLoader的parent层级为:
//PathClassLoader(apk)-->PathClassLoader(system)->BootClassLoader
//所以一般情况下,传入的ClassLoader的parent就是系统的PathClassLoader, 从而递归调用只会调用两次,即
//h_parent第一次等于PathClassLoader(system),第二次h_parent等于BootClassLoader
bool recursive_result = FindClassInPathClassLoader(soa, self, descriptor, hash, h_parent, result);
if (!recursive_result) {
// Something wrong up the chain.
return false;
}
if (*result != nullptr) {
// Found the class up the chain.
return true;
}
//获取DexFile的mCookie变量,mCookie指向的是已加载的dex文件列表
ArtField* const cookie_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie);
//获取DexPathList的dexElements
ArtField* const dex_file_field =
soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
//获取PathClassLoader的pathList属性
mirror::Object* dex_path_list =
soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)->
GetObject(class_loader.Get());
if (dex_path_list != nullptr && dex_file_field != nullptr && cookie_field != nullptr) {
mirror::Object* dex_elements_obj =
soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)->
GetObject(dex_path_list);
if (dex_elements_obj != nullptr) {
Handle> dex_elements =
hs.NewHandle(dex_elements_obj->AsObjectArray());
for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
mirror::Object* element = dex_elements->GetWithoutChecks(i);
if (element == nullptr) {
// Should never happen, fall back to java code to throw a NPE.
break;
}
mirror::Object* dex_file = dex_file_field->GetObject(element);
if (dex_file != nullptr) {
//将mCookie转换为LongArray*类型
mirror::LongArray* long_array = cookie_field->GetObject(dex_file)->AsLongArray();
if (long_array == nullptr) {
break;
}
int32_t long_array_size = long_array->GetLength();
for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) {
//将LongArray转换为DexFile*类型
const DexFile* cp_dex_file = reinterpret_cast(static_cast(
long_array->GetWithoutChecks(j)));
//查找ClassDef
const DexFile::ClassDef* dex_class_def = cp_dex_file->FindClassDef(descriptor, hash);
if (dex_class_def != nullptr) {
//解析类,加载属性,方法
mirror::Class* klass = DefineClass(self,
descriptor,
hash,
class_loader,
*cp_dex_file,
*dex_class_def);
if (klass == nullptr) {
self->ClearException();
return true;
}
*result = klass;
return true;
}
}
}
}
}
self->AssertNoPendingException();
}
// Result is still null from the parent call, no need to set it again...
return true;
}
FindClassInPathClassLoader
主要逻辑是递归的在传入的ClassLoader的各级parent中依次查找类(典型的双亲委派模式) , 一般情况下,一个应用的PathClassLoader的parent层级为:`PathClassLoader(apk)-->PathClassLoader(system)->BootClassLoader`所以一般情况下,传入的ClassLoader的parent就是系统的PathClassLoader, 从而递归调用只会调用两次,即h_parent第一次等于PathClassLoader(system),第二次h_parent等于BootClassLoader. 在双亲中如果找到类,则直接返回,如果没有找到,则依次获取几个重要的变量BaseDexClassLoader.pathList, DexPathList.dexElement, DexFile.mCookie
,根据这几个变量在传入的ClassLoader所加载的dex文件列表中查找类
4. 总结
一般而言,反射获取一个类时会调用Class.forName(String)
,获取类的过程可以总结为以下几步:
- 根据函数调用栈帧获取调用者的ClassLoader(如果调用的是
Class.forName(String, boolean, ClassLoader)
,就没有根据栈帧获取ClassLoader这一步) - 每一个ClassLoader都有一个ClassTable,用来缓存已经加载的类.如果传入的ClassLoader为null,就在BootClassLoader对应的
boot_class_table_
中查找,如果ClassLaoder不为null,就在ClassLoader对应的ClassTable中查找;如果找到Class,确保Class已经解析后,返回,否则进入下一步 - 如果没有在缓存的ClassTable中找到类,首先判断传入的ClassLoader是否为null,如果是,就在
boot_class_path_
中查找,如果不是,则递归的依次在传入的ClassLoader各级parent以及自身当中查找类(除了BootClassLoader
,其余parent以及自身ClassLoader都必须是PathClassLoader
,查找类主要是通过在Java层的几个重要变量完成:BaseDexClassLoader.pathList, DexPathList.dexElement, DexFile.mCookie
),如果找到则返回(查找的过程中,如果找到了类,会完成对类的解析过程),如果没找到则再进入下一步 - 以上几步都没有找到的话,再调用传入的ClassLoader的
loadClass
进行最后一次查找(loadClass
的过程中如果找到类,也会完成对类的解析),找到则返回,没找到则抛出异常