動態代理類生成從JDK到Hotspot

  本來想着從頭開始寫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

https://www.cnblogs.com/porter/p/9399716.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章