本来想着从头开始写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变量(这里的初始化不是指
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 对象,这里看看添加构造函数
private ProxyGenerator.MethodInfo generateConstructor() throws IOException {
ProxyGenerator.MethodInfo var1 = new ProxyGenerator.MethodInfo("", "(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", "", "(Ljava/lang/reflect/InvocationHandler;)V"));
var2.writeByte(177);
var1.maxStack = 10;
var1.maxLocals = 2;
var1.declaredExceptions = new short[0];
return var1;
}
第一个参数
第二个参数方法形参和方法返回值,构造函数形参 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* cp_patches,
TempNewSymbol& parsed_name,
bool verify,
TRAPS) {
这个方法中完成了链接操作即验证、解析、准备阶段;整个解析流程比较长,看一下解析的流程如下;
// 字节码文件解析
instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
ClassLoaderData* loader_data,
Handle protection_domain,
KlassHandle host_klass,
GrowableArray* 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* 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* 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* 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 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* 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
https://www.cnblogs.com/porter/p/9399716.html