本來想着從頭開始寫JVM但是之前寫了動態代理設計模式,而動態代理模式中又涉及到動態生成Class對象的過程,索性就先了解一下對象生成過程,在後續學習過程如果發現寫的有問題在糾正和補充!
一、動態代理類生成主流程
1、類加載、代理類實現接口Class對象集合獲取
2、校驗是否爲爲接口(java是單繼承而動態生成的代理李繼承了Proxy所以其他的只能是接口)
3、判斷接口是不是public的,如果不是public則要判斷是否爲同一個目錄下的,如果不是同一目錄下的則生成代理類結束
4、生成代理類包名、類名組裝
5、按照代理類實現接口Class對象動態生成字節碼文件
6、調用native 方法對動態生成的字節碼文件進行驗證、魔數、版本號
7、字節碼文件進行解析
8、根據ClassLoader 創建Klass對象,Klass對象對應java中的Class對象
9、解析信息回填到Klass對象
10、Klass對象內存空間分配並初始化static變量(這裏的初始化不是指<cinit>方法的執行)
11、返回Class對象
二、以主流程爲主要架構,跟進查看具體實現和部分細節實現
1、類加載器、代理類實現接口Class對象集合
2、校驗是否爲爲接口(java是單繼承而動態生成的代理李繼承了Proxy所以其他的只能是接口)
3、判斷接口是不是public的,如果不是public則要判斷是否爲同一個目錄下的,如果不是同一目錄下的則生成代理類結束
4、代理類包名獲取
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
public static final String PROXY_PACKAGE = "com.sun.proxy";
5、生成代理類類名
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy”;
這就是我們看到的生成代理類類名稱 com.sun.proxy.$Pxoy0、com.sun.proxy.$Pxoy1
6、獲取代理類字節碼字節流(.class 文件)
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
(1)、調用ProxyGenerator.generateProxyClass方法,參數類名、接口數組、訪問權限
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
(2)、獲取字節碼文件generateClassFile()方法
看方法名稱就明白,是用來獲取.class 文件字節碼的,那就是要組裝一個滿足.class 文件格式的字節流
(3)、addProxyMethod 組裝代理類方法
((List)var8).add(new ProxyGenerator.ProxyMethod(var3, var4, var5, var6, var2, null));
創建一個標識方法的對象ProxyMethod
(4)、方法元數據描述對象ProxyMethod 的成員變量
private class ProxyMethod {
public String methodName;
public Class<?>[] parameterTypes;
public Class<?> returnType;
public Class<?>[] exceptionTypes;
public Class<?> fromClass;
public String methodFieldName;
看到這些變量是不是很熟悉,方法名、方法參數類型、方法返回值類型、異常類型、方法所屬類、方法屬性名稱即動態生成的代理類中Method類的變量名。
看構造函數中的變量名稱;
(5)、添加完默認的equals、hashCode、toString方法之後遍歷接口,獲取接口所有方法並添加到
proxyMethods 集合;這個對象組裝的有點像常量池中的符號引用。
(6)、生成 MethodInfo 對象,這裏看看添加構造函數<init>
private ProxyGenerator.MethodInfo generateConstructor() throws IOException {
ProxyGenerator.MethodInfo var1 = new ProxyGenerator.MethodInfo("<init>", "(Ljava/lang/reflect/InvocationHandler;)V", 1);
DataOutputStream var2 = new DataOutputStream(var1.code);
this.code_aload(0, var2);
this.code_aload(1, var2);
var2.writeByte(183);
var2.writeShort(this.cp.getMethodRef("java/lang/reflect/Proxy", "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));
var2.writeByte(177);
var1.maxStack = 10;
var1.maxLocals = 2;
var1.declaredExceptions = new short[0];
return var1;
}
第一個參數<init> 方法名稱
第二個參數方法形參和方法返回值,構造函數形參 InvocationHandler 對象
第三個參數方法的訪問權限
(7)、代理類中屬性添加
while(var15.hasNext()) {
ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
this.methods.add(var16.generateMethod());
}
(8)、動態組裝的字節碼文件輸出到字節流
ByteArrayOutputStream var13 = new ByteArrayOutputStream();
DataOutputStream var14 = new DataOutputStream(var13);
代理類字節流動態生成。
OK 到這裏JVM字節碼文件生成了。下面看看按照字節碼文件如何生成Class對象。
疑問:
上面的MethodInfo 動態代理類生成的方法信息描述,ProxyMethod 是動態代理類中Method 屬性的描述?
加載字節碼文件後Class對象生成過程
7、defineClass0調用native方法解析字節碼文件生成Class對象
private static native Class<?> defineClass0(ClassLoader loader, String name,
byte[] b, int off, int len);
(1)、調用的是native方法,我們看jdk中的實現
目錄: jdk/share/native/java/lang /classLoader.c
調用的native方法 如下
JNIEXPORT jclass JNICALL
Java_java_lang_ClassLoader_defineClass0(JNIEnv *env,
jobject loader,
jstring name,
jbyteArray data,
jint offset,
jint length,
jobject pd)
{
return Java_java_lang_ClassLoader_defineClass1(env, loader, name, data, offset,length, pd, NULL);
}
(2)、調用Java_java_lang_ClassLoader_defineClass1 方法
result = JVM_DefineClassWithSource(env, utfName, loader, body, length, pd, utfSource);
調用JVM_DefineClassWithSource 生成jclass 文件
(3)、JVM_DefineClassWithSource 方法
目錄: /hotspot/src/share/vm/prims/jvm.cpp
JVM_ENTRY(jclass, JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source))
JVMWrapper2("JVM_DefineClassWithSource %s", name);
return jvm_define_class_common(env, name, loader, buf, len, pd, source, true, THREAD);
JVM_END
(4)、調用公共方法jvm_define_class_common
// common code for JVM_DefineClass() and JVM_DefineClassWithSource()
// and JVM_DefineClassWithSourceCond()
static jclass jvm_define_class_common(JNIEnv *env, const char *name,
jobject loader, const jbyte *buf,
jsize len, jobject pd, const char *source,
jboolean verify, TRAPS) {
if (source == NULL) source = "__JVM_DefineClass__";
assert(THREAD->is_Java_thread(), "must be a JavaThread");
JavaThread* jt = (JavaThread*) THREAD;
// Since exceptions can be thrown, class initialization can take place
// if name is NULL no check for class name in .class stream has to be made.
TempNewSymbol class_name = NULL;
if (name != NULL) {
const int str_len = (int)strlen(name);
if (str_len > Symbol::max_length()) {
// It's impossible to create this class; the name cannot fit
// into the constant pool.
THROW_MSG_0(vmSymbols::java_lang_NoClassDefFoundError(), name);
}
class_name = SymbolTable::new_symbol(name, str_len, CHECK_NULL);
}
ResourceMark rm(THREAD);
ClassFileStream st((u1*) buf, len, (char *)source);
Handle class_loader (THREAD, JNIHandles::resolve(loader));
if (UsePerfData) {
is_lock_held_by_thread(class_loader,
ClassLoader::sync_JVMDefineClassLockFreeCounter(),
THREAD);
}
Handle protection_domain (THREAD, JNIHandles::resolve(pd));
Klass* k = SystemDictionary::resolve_from_stream(class_name, class_loader,
protection_domain, &st,
verify != 0,
CHECK_NULL);
return (jclass) JNIHandles::make_local(env, k->java_mirror());
}
刪除了部分代碼,主要看生成Klass對象方法
(5)、Klass* SystemDictionary::resolve_from_stream() 方法
目錄:hotspot/src/share/vm/classfile/systemDictionary.cpp
Klass* SystemDictionary::resolve_from_stream(Symbol* class_name,
Handle class_loader,
Handle protection_domain,
ClassFileStream* st,
bool verify,
TRAPS)
方法參數: 類名稱、類加載器、對象、字節碼文件字節流
(6)、調用解析類解析方法對字節碼文件進行解析、驗證
instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
loader_data,
protection_domain,
parsed_name,
verify,
THREAD);
(7)、字節碼文件解析類
目錄: hotspot/src/share/vm/classfile/classFileParser.hpp
instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
ClassLoaderData* loader_data,
Handle protection_domain,
KlassHandle host_klass,
GrowableArray<Handle>* cp_patches,
TempNewSymbol& parsed_name,
bool verify,
TRAPS) {
這個方法中完成了鏈接操作即驗證、解析、準備階段;整個解析流程比較長,看一下解析的流程如下;
// 字節碼文件解析
instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
ClassLoaderData* loader_data,
Handle protection_domain,
KlassHandle host_klass,
GrowableArray<Handle>* cp_patches,
TempNewSymbol& parsed_name,
bool verify,
TRAPS) {
// When a retransformable agent is attached, JVMTI caches the
// class bytes that existed before the first retransformation.
// If RedefineClasses() was used before the retransformable
// agent attached, then the cached class bytes may not be the
// original class bytes.
JvmtiCachedClassFileData *cached_class_file = NULL;
Handle class_loader(THREAD, loader_data->class_loader());
bool has_default_methods = false;
ResourceMark rm(THREAD);
ClassFileStream* cfs = stream();
// Timing
assert(THREAD->is_Java_thread(), "must be a JavaThread");
JavaThread* jt = (JavaThread*) THREAD;
PerfClassTraceTime ctimer(ClassLoader::perf_class_parse_time(),
ClassLoader::perf_class_parse_selftime(),
NULL,
jt->get_thread_stat()->perf_recursion_counts_addr(),
jt->get_thread_stat()->perf_timers_addr(),
PerfClassTraceTime::PARSE_CLASS);
init_parsed_class_attributes(loader_data);
if (JvmtiExport::should_post_class_file_load_hook()) {
// Get the cached class file bytes (if any) from the class that
// is being redefined or retransformed. We use jvmti_thread_state()
// instead of JvmtiThreadState::state_for(jt) so we don't allocate
// a JvmtiThreadState any earlier than necessary. This will help
// avoid the bug described by 7126851.
JvmtiThreadState *state = jt->jvmti_thread_state();
if (state != NULL) {
KlassHandle *h_class_being_redefined =
state->get_class_being_redefined();
if (h_class_being_redefined != NULL) {
instanceKlassHandle ikh_class_being_redefined =
instanceKlassHandle(THREAD, (*h_class_being_redefined)());
//之前緩存數據獲取
cached_class_file = ikh_class_being_redefined->get_cached_class_file();
}
}
unsigned char* ptr = cfs->buffer();
unsigned char* end_ptr = cfs->buffer() + cfs->length();
JvmtiExport::post_class_file_load_hook(name, class_loader(), protection_domain,
&ptr, &end_ptr, &cached_class_file);
if (ptr != cfs->buffer()) {
// JVMTI agent has modified class file data.
// Set new class file stream using JVMTI agent modified
// class file data.
cfs = new ClassFileStream(ptr, end_ptr - ptr, cfs->source());
set_stream(cfs);
}
}
_host_klass = host_klass;
_cp_patches = cp_patches;
instanceKlassHandle nullHandle;
// Figure out whether we can skip format checking (matching classic VM behavior)
_need_verify = Verifier::should_verify_for(class_loader(), verify);
// Set the verify flag in stream
cfs->set_verify(_need_verify);
// Save the class file name for easier error message printing.
// 保存類文件名,以便打印錯誤信息
_class_name = (name != NULL) ? name : vmSymbols::unknown_class_name();
cfs->guarantee_more(8, CHECK_(nullHandle)); // magic, major, minor
// Magic value
// .class 文件開頭魔數獲取
u4 magic = cfs->get_u4_fast();
guarantee_property(magic == JAVA_CLASSFILE_MAGIC,
"Incompatible magic value %u in class file %s",
magic, CHECK_(nullHandle));
// Version numbers
// jdk版本號獲取
u2 minor_version = cfs->get_u2_fast();
u2 major_version = cfs->get_u2_fast();
// Check version numbers - we check this even with verifier off
// 校驗當前jvm是否支持該版本、不支持則拋出異常提示信息當前major、minor版本不支持
if (!is_supported_version(major_version, minor_version)) {
if (name == NULL) {
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_UnsupportedClassVersionError(),
"Unsupported major.minor version %u.%u",
major_version,
minor_version);
} else {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_UnsupportedClassVersionError(),
"%s : Unsupported major.minor version %u.%u",
name->as_C_string(),
major_version,
minor_version);
}
return nullHandle;
}
_major_version = major_version;
_minor_version = minor_version;
// Check if verification needs to be relaxed for this class file
// Do not restrict it to jdk1.0 or jdk1.1 to maintain backward compatibility (4982376)
_relax_verify = Verifier::relax_verify_for(class_loader());
// Constant pool
// 常量池解析
constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle));
// 常量池長度
int cp_size = cp->length();
// cfs= class file strem
cfs->guarantee_more(8, CHECK_(nullHandle)); // flags, this_class, super_class, infs_len
// Access flags
AccessFlags access_flags;
jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS;
if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
// Set abstract bit for old class files for backward compatibility
flags |= JVM_ACC_ABSTRACT;
}
verify_legal_class_modifiers(flags, CHECK_(nullHandle));
access_flags.set_flags(flags);
// This class and superclass
// 本類、父類重常量池獲取符號引用(應該沒記錯)
u2 this_class_index = cfs->get_u2_fast();
check_property(
valid_cp_range(this_class_index, cp_size) &&
cp->tag_at(this_class_index).is_unresolved_klass(),
"Invalid this class index %u in constant pool in class file %s",
this_class_index, CHECK_(nullHandle));
Symbol* class_name = cp->unresolved_klass_at(this_class_index);
assert(class_name != NULL, "class_name can't be null");
// It's important to set parsed_name *before* resolving the super class.
// (it's used for cleanup by the caller if parsing fails)
parsed_name = class_name;
// parsed_name is returned and can be used if there's an error, so add to
// its reference count. Caller will decrement the refcount.
parsed_name->increment_refcount();
// Update _class_name which could be null previously to be class_name
_class_name = class_name;
// Don't need to check whether this class name is legal or not.
// It has been checked when constant pool is parsed.
// However, make sure it is not an array type.
if (_need_verify) {
guarantee_property(class_name->byte_at(0) != JVM_SIGNATURE_ARRAY,
"Bad class name in class file %s",
CHECK_(nullHandle));
}
Klass* preserve_this_klass; // for storing result across HandleMark
// release all handles when parsing is done
{ HandleMark hm(THREAD);
// Checks if name in class file matches requested name
if (name != NULL && class_name != name) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_NoClassDefFoundError(),
"%s (wrong name: %s)",
name->as_C_string(),
class_name->as_C_string()
);
return nullHandle;
}
if (TraceClassLoadingPreorder) {
tty->print("[Loading %s", (name != NULL) ? name->as_klass_external_name() : "NoName");
if (cfs->source() != NULL) tty->print(" from %s", cfs->source());
tty->print_cr("]");
}
u2 super_class_index = cfs->get_u2_fast();
instanceKlassHandle super_klass = parse_super_class(super_class_index,
CHECK_NULL);
// Interfaces
u2 itfs_len = cfs->get_u2_fast();
// 接口解析
Array<Klass*>* local_interfaces =
parse_interfaces(itfs_len, protection_domain, _class_name,
&has_default_methods, CHECK_(nullHandle));
u2 java_fields_count = 0;
// Fields (offsets are filled in later)
FieldAllocationCount fac;
Array<u2>* fields = parse_fields(class_name,
access_flags.is_interface(),
&fac, &java_fields_count,
CHECK_(nullHandle));
// Methods
// 方法解析
bool has_final_method = false;
AccessFlags promoted_flags;
promoted_flags.set_flags(0);
Array<Method*>* methods = parse_methods(access_flags.is_interface(),
&promoted_flags,
&has_final_method,
&has_default_methods,
CHECK_(nullHandle));
// Additional attributes
ClassAnnotationCollector parsed_annotations;
parse_classfile_attributes(&parsed_annotations, CHECK_(nullHandle));
// Make sure this is the end of class file stream
guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle));
// We check super class after class file is parsed and format is checked
if (super_class_index > 0 && super_klass.is_null()) {
Symbol* sk = cp->klass_name_at(super_class_index);
if (access_flags.is_interface()) {
// Before attempting to resolve the superclass, check for class format
// errors not checked yet.
guarantee_property(sk == vmSymbols::java_lang_Object(),
"Interfaces must have java.lang.Object as superclass in class file %s",
CHECK_(nullHandle));
}
Klass* k = SystemDictionary::resolve_super_or_fail(class_name, sk,
class_loader,
protection_domain,
true,
CHECK_(nullHandle));
KlassHandle kh (THREAD, k);
super_klass = instanceKlassHandle(THREAD, kh());
}
if (super_klass.not_null()) {
if (super_klass->has_default_methods()) {
has_default_methods = true;
}
if (super_klass->is_interface()) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IncompatibleClassChangeError(),
"class %s has interface %s as super class",
class_name->as_klass_external_name(),
super_klass->external_name()
);
return nullHandle;
}
// Make sure super class is not final
if (super_klass->is_final()) {
THROW_MSG_(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class", nullHandle);
}
}
// save super klass for error handling.
_super_klass = super_klass;
// Compute the transitive list of all unique interfaces implemented by this class
_transitive_interfaces =
compute_transitive_interfaces(super_klass, local_interfaces, CHECK_(nullHandle));
// sort methods
intArray* method_ordering = sort_methods(methods);
// promote flags from parse_methods() to the klass' flags
access_flags.add_promoted_flags(promoted_flags.as_int());
// Size of Java vtable (in words)
int vtable_size = 0;
int itable_size = 0;
int num_miranda_methods = 0;
GrowableArray<Method*> all_mirandas(20);
klassVtable::compute_vtable_size_and_num_mirandas(
&vtable_size, &num_miranda_methods, &all_mirandas, super_klass(), methods,
access_flags, class_loader, class_name, local_interfaces,
CHECK_(nullHandle));
// Size of Java itable (in words)
itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(_transitive_interfaces);
FieldLayoutInfo info;
layout_fields(class_loader, &fac, &parsed_annotations, &info, CHECK_NULL);
int total_oop_map_size2 =
InstanceKlass::nonstatic_oop_map_size(info.total_oop_map_count);
// Compute reference type
ReferenceType rt;
if (super_klass() == NULL) {
rt = REF_NONE;
} else {
rt = super_klass->reference_type();
}
// We can now create the basic Klass* for this klass
// 根據ClassLoader 創建Klass對象
_klass = InstanceKlass::allocate_instance_klass(loader_data,
vtable_size,
itable_size,
info.static_field_size,
total_oop_map_size2,
rt,
access_flags,
name,
super_klass(),
!host_klass.is_null(),
CHECK_(nullHandle));
instanceKlassHandle this_klass (THREAD, _klass);
assert(this_klass->static_field_size() == info.static_field_size, "sanity");
assert(this_klass->nonstatic_oop_map_count() == info.total_oop_map_count,
"sanity");
// Fill in information already parsed
// 填寫已解析信息
this_klass->set_should_verify_class(verify);
jint lh = Klass::instance_layout_helper(info.instance_size, false);
this_klass->set_layout_helper(lh);
assert(this_klass->oop_is_instance(), "layout is correct");
assert(this_klass->size_helper() == info.instance_size, "correct size_helper");
// Not yet: supers are done below to support the new subtype-checking fields
//this_klass->set_super(super_klass());
this_klass->set_class_loader_data(loader_data);
this_klass->set_nonstatic_field_size(info.nonstatic_field_size);
this_klass->set_has_nonstatic_fields(info.has_nonstatic_fields);
this_klass->set_static_oop_field_count(fac.count[STATIC_OOP]);
apply_parsed_class_metadata(this_klass, java_fields_count, CHECK_NULL);
if (has_final_method) {
this_klass->set_has_final_method();
}
this_klass->copy_method_ordering(method_ordering, CHECK_NULL);
// The InstanceKlass::_methods_jmethod_ids cache
// is managed on the assumption that the initial cache
// size is equal to the number of methods in the class. If
// that changes, then InstanceKlass::idnum_can_increment()
// has to be changed accordingly.
this_klass->set_initial_method_idnum(methods->length());
this_klass->set_name(cp->klass_name_at(this_class_index));
if (is_anonymous()) // I am well known to myself
cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
// 填寫已解析版本號信息
this_klass->set_minor_version(minor_version);
this_klass->set_major_version(major_version);
this_klass->set_has_default_methods(has_default_methods);
// Set up Method*::intrinsic_id as soon as we know the names of methods.
// (We used to do this lazily, but now we query it in Rewriter,
// which is eagerly done for every method, so we might as well do it now,
// when everything is fresh in memory.)
if (Method::klass_id_for_intrinsics(this_klass()) != vmSymbols::NO_SID) {
for (int j = 0; j < methods->length(); j++) {
methods->at(j)->init_intrinsic_id();
}
}
if (cached_class_file != NULL) {
// JVMTI: we have an InstanceKlass now, tell it about the cached bytes
// InstanceKlass 對象緩存
this_klass->set_cached_class_file(cached_class_file);
}
// Fill in field values obtained by parse_classfile_attributes
if (parsed_annotations.has_any_annotations())
parsed_annotations.apply_to(this_klass);
apply_parsed_class_attributes(this_klass);
// Miranda methods
if ((num_miranda_methods > 0) ||
// if this class introduced new miranda methods or
(super_klass.not_null() && (super_klass->has_miranda_methods()))
// super class exists and this class inherited miranda methods
) {
this_klass->set_has_miranda_methods(); // then set a flag
}
// Fill in information needed to compute superclasses.
// 初始化super類的信息
this_klass->initialize_supers(super_klass(), CHECK_(nullHandle));
// Initialize itable offset tables
klassItable::setup_itable_offset_table(this_klass);
// Compute transitive closure of interfaces this class implements
// Do final class setup
fill_oop_maps(this_klass, info.nonstatic_oop_map_count, info.nonstatic_oop_offsets, info.nonstatic_oop_counts);
// Fill in has_finalizer, has_vanilla_constructor, and layout_helper
set_precomputed_flags(this_klass);
// reinitialize modifiers, using the InnerClasses attribute
int computed_modifiers = this_klass->compute_modifier_flags(CHECK_(nullHandle));
this_klass->set_modifier_flags(computed_modifiers);
// check if this class can access its super class
check_super_class_access(this_klass, CHECK_(nullHandle));
// check if this class can access its superinterfaces
check_super_interface_access(this_klass, CHECK_(nullHandle));
// check if this class overrides any final method
check_final_method_override(this_klass, CHECK_(nullHandle));
// check that if this class is an interface then it doesn't have static methods
if (this_klass->is_interface()) {
/* An interface in a JAVA 8 classfile can be static */
if (_major_version < JAVA_8_VERSION) {
check_illegal_static_method(this_klass, CHECK_(nullHandle));
}
}
// Allocate mirror and initialize static fields
//// 初始化分配的static字段
// 1.必須加載Class對象實例(mirror),它用於分配空間
// 2.創建java.lang.Class instance並分配空間
// 3.建立 mirror(java.lang.Class instance)-》klass的關係(對應Metadata中的klass關係)
// 4.判斷是否是數組(普通數組/object數組)
// 5.初始化mirror的field
// 5.1 獲取到該類的field,找到靜態的變量,並初始化
java_lang_Class::create_mirror(this_klass, protection_domain, CHECK_(nullHandle));
// Generate any default methods - default methods are interface methods
// that have a default implementation. This is new with Lambda project.
if (has_default_methods ) {
DefaultMethods::generate_default_methods(
this_klass(), &all_mirandas, CHECK_(nullHandle));
}
// Update the loader_data graph.
//記錄this_klass的類中依賴,以便後續進行GC
record_defined_class_dependencies(this_klass, CHECK_NULL);
ClassLoadingService::notify_class_loaded(InstanceKlass::cast(this_klass()),
false /* not shared class */);
if (TraceClassLoading) {
ResourceMark rm;
// print in a single call to reduce interleaving of output
if (cfs->source() != NULL) {
tty->print("[Loaded %s from %s]\n", this_klass->external_name(),
cfs->source());
} else if (class_loader.is_null()) {
if (THREAD->is_Java_thread()) {
Klass* caller = ((JavaThread*)THREAD)->security_get_caller_class(1);
tty->print("[Loaded %s by instance of %s]\n",
this_klass->external_name(),
InstanceKlass::cast(caller)->external_name());
} else {
tty->print("[Loaded %s]\n", this_klass->external_name());
}
} else {
tty->print("[Loaded %s from %s]\n", this_klass->external_name(),
InstanceKlass::cast(class_loader->klass())->external_name());
}
}
if (TraceClassResolution) {
ResourceMark rm;
// print out the superclass.
const char * from = this_klass()->external_name();
if (this_klass->java_super() != NULL) {
tty->print("RESOLVE %s %s (super)\n", from, InstanceKlass::cast(this_klass->java_super())->external_name());
}
// print out each of the interface classes referred to by this class.
Array<Klass*>* local_interfaces = this_klass->local_interfaces();
if (local_interfaces != NULL) {
int length = local_interfaces->length();
for (int i = 0; i < length; i++) {
Klass* k = local_interfaces->at(i);
InstanceKlass* to_class = InstanceKlass::cast(k);
const char * to = to_class->external_name();
tty->print("RESOLVE %s %s (interface)\n", from, to);
}
}
}
// preserve result across HandleMark
preserve_this_klass = this_klass();
}
// Create new handle outside HandleMark (might be needed for
// Extended Class Redefinition)
instanceKlassHandle this_klass (THREAD, preserve_this_klass);
debug_only(this_klass->verify();)
// Clear class if no error has occurred so destructor doesn't deallocate it
_klass = NULL;
// 返回結果即Klass 對象
return this_klass;
}
三、總結
1、動態代理類生成主要由兩部分組即java代碼實現動態字節碼文件生成和c、c++部分實現的驗證、解析字節碼文件即.class 文件來生成Class對象。
2、平時使用時類對象的創建流程爲:類加載、驗證、解析、準備、初始化、對象創建、使用、卸載,這裏動態生成時相當於省去了類加載這一步,因爲是在程序運行時動態生成並且是在內存中。
3、oop-klass 模型在之後jvm學習過程中注意一下。
4、其中第一部分java實現的動態生成字節碼文件的方式除了現在jdk提供的這種方式還有很多,比如性能比較高的AWS和使用比較方便的Javassist 框架來編寫字節碼文件。
下一篇文章中我們學習一下Javassist 字節碼框架並看看dubbo中用它生成代理類的實現……
參考文章:
https://www.jianshu.com/p/b6cb4c694951
https://www.jianshu.com/p/b57a83ad8baa
https://blog.csdn.net/qq_31430665/article/details/106689164?%3E