微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

JVM之类的热替换原理解读,架构师培训视频百度云

                                                  the_class_sym,

                                                  the_class_loader,

                                                  protection_domain,

                                                  &st,

......

}




上面这个方法调用了parse\_stream(),从文件流中解析类,最终触发类的重新加载:



InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,

                                               Handle class_loader,

                                               Handle protection_domain, TRAPS) {

......



InstanceKlass* new_ik = KlassFactory::check_shared_class_file_load_hook(

    ik, class_name, class_loader, protection_domain, CHECK_NULL);



if (new_ik != NULL) {

  return new_ik;

}

return ik;

}




这里又调用了KlassFactory::check\_shared\_class\_file\_load\_hook(),看名字就知道是个hook方法,它会调用post\_class\_file\_load\_hook(),利用jvmtiClassFileLoadHookPoster来通知修改器进行类的修改。



消息的处理者为:eventHandlerClassFileLoadHook():



void JNICALL

eventHandlerClassFileLoadHook( jvmtiEnv * jvmtienv,

                            jnienv *                jnienv,

                            jclass                  class_being_redefined,

                            jobject                 loader,

                            const char*             name,

                            jobject                 protectionDomain,

                            jint                    class_data_len,

                            const unsigned char*    class_data,

                            jint*                   new_class_data_len,

                            unsigned char**         new_class_data) {

jplISEnvironment * environment  = NULL;



environment = getjplISEnvironment(jvmtienv);



/* if something is internally inconsistent (no agent), just silently return without touching the buffer */

if ( environment != NULL ) {

    jthrowable outstandingException = preserveThrowable(jnienv);

    transformClassFile( environment->mAgent,

                        jnienv,

                        loader,

                        name,

                        class_being_redefined,

                        protectionDomain,

                        class_data_len,

                        class_data,

                        new_class_data_len,

                        new_class_data,

                        environment->mIsRetransformer);

    restoreThrowable(jnienv, outstandingException);

}

}




eventHandlerClassFileLoadHook()在收到消息后,会调用transformClassFile():



void

transformClassFile( jplISAgent * agent,

                            jnienv *                jnienv,

                            jobject                 loaderObject,

                            const char*             name,

                            jclass                  classBeingredefined,

                            jobject                 protectionDomain,

                            jint                    class_data_len,

                            const unsigned char*    class_data,

                            jint*                   new_class_data_len,

                            unsigned char**         new_class_data,

                            jboolean                is_retransformer) {

        ......

        transformedBufferObject = (*jnienv)->CallObjectMethod(

                                            jnienv,

                                            agent->mInstrumentationImpl,

                                            agent->mTransform,

                                            moduleObject,

                                            loaderObject,

                                            classNameStringObject,

                                            classBeingredefined,

                                            protectionDomain,

                                            classfilebufferObject,

                                            is_retransformer);

     ......

}




这里会利用JNI调用 java 层InstrumentationImpl的transform(),你看,我们又绕到Java层了:



private byte[] transform( Module module,

            ClassLoader         loader,

            String              classname,

            Class<?>            classBeingredefined,

            ProtectionDomain    protectionDomain,

            byte[]              classfilebuffer,

            boolean             isRetransformer) {

    TransformerManager mgr = isRetransformer?

                                    mRetransfomableTransformerManager :

                                    mTransformerManager;

    // module is null when not a class load or when loading a class in an

    // unnamed module and this is the first type to be loaded in the package.

    if (module == null) {

        if (classBeingredefined != null) {

            module = classBeingredefined.getModule();

        } else {

            module = (loader == null) ? jdk.internal.loader.BootLoader.getUnnamedModule()

                                      : loader.getUnnamedModule();

        }

    }

    if (mgr == null) {

        return null; // no manager, no transform

    } else {

        return mgr.transform(   module,

                                loader,

                                classname,

                                classBeingredefined,

                                protectionDomain,

                                classfilebuffer);

    }

} 



上面主要就是调用TransformerManager的transform():



public byte[] transform( Module module,

            ClassLoader         loader,

            String              classname,

            Class<?>            classBeingredefined,

            ProtectionDomain    protectionDomain,

            byte[]              classfilebuffer) {

    boolean someonetouchedTheBytecode = false;



    TransformerInfo[]  transformerList = getSnapshottransformerList();



    byte[]  bufferToUse = classfilebuffer;



    // order matters, gotta run 'em in the order they were added

    for ( int x = 0; x < transformerList.length; x++ ) {

        TransformerInfo         transformerInfo = transformerList[x];

        ClassFileTransformer    transformer = transformerInfo.transformer();

        byte[]                  transformedBytes = null;



        try {

            transformedBytes = transformer.transform(   module,

                                                        loader,

                                                        classname,

                                                        classBeingredefined,

                                                        protectionDomain,

                                                        bufferToUse);

        }

        catch (Throwable t) {

            // don't let any one transformer mess it up for the others.

            // This is where we need to put some logging. What should go here? FIXME

        }



        if ( transformedBytes != null ) {

            someonetouchedTheBytecode = true;

            bufferToUse = transformedBytes;

        }

    }



    // if someone modified it, return the modified buffer.

    // otherwise return null to mean "no transforms occurred"

    byte [] result;

    if ( someonetouchedTheBytecode ) {

        result = bufferToUse;

    }

    else {

        result = null;

    }



    return result;

} 



看到这儿,大家还记得我们开始的时候,会将我们自定义的ClassFileTransformer对象注册到TransformerManager中吗?这里终于派上用场了,TransformerManager的transform()方法会遍历它的注册数组,调用每个ClassFileTransformer对象的transform()方法,并将我们修改后的类字节码返回,返回后的字节码最终又回到了上面JVM层的transformClassFile()中,并最终交还给给class\_file\_load\_hook 消息的发送方。



让我们回到消息的发送方:check\_shared\_class\_file\_load\_hook()中去看看:



InstanceKlass* KlassFactory::check_shared_class_file_load_hook(

                                      InstanceKlass* ik,

                                      Symbol* class_name,

                                      Handle class_loader,

                                      Handle protection_domain, TRAPS) {

#if INCLUDE_CDS && INCLUDE_jvmti

assert(ik != NULL, “sanity”);

assert(ik->is_shared(), “expecting a shared class”);

if (jvmtiExport::should_post_class_file_load_hook()) {

assert(THREAD->is_Java_thread(), "must be JavaThread");



// Post the CFLH

jvmtiCachedClassFileData* cached_class_file = NULL;

jvmtiCachedClassFileData* archived_class_data = ik->get_archived_class_data();

assert(archived_class_data != NULL, "shared class has no archived class data");

unsigned char* ptr =

    VM_redefineClasses::get_cached_class_file_bytes(archived_class_data);

unsigned char* end_ptr =

    ptr + VM_redefineClasses::get_cached_class_file_len(archived_class_data);

unsigned char* old_ptr = ptr;

jvmtiExport::post_class_file_load_hook(class_name,

                                       class_loader,

                                       protection_domain,

                                       &ptr,

                                       &end_ptr,

                                       &cached_class_file);

// 这里判断类是否被修改了

if (old_ptr != ptr) {

  ......

  // 根据返回的类字节码指针及指针范围,构造ClassFileStream

  ClassFileStream* stream = new ClassFileStream(ptr,

                                                end_ptr - ptr,

                                                pathname,

                                                ClassFileStream::verify);

最后

这份清华大牛整理的进大厂必备的redis视频、面试题和技术文档

**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](

)**

祝大家早日进入大厂,拿到满意的薪资和职级~~~加油!!

感谢大家的支持!!

image.png

  ClassFileStream* stream = new ClassFileStream(ptr,

                                                end_ptr - ptr,

                                                pathname,

                                                ClassFileStream::verify);

最后

这份清华大牛整理的进大厂必备的redis视频、面试题和技术文档

**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](

)**

祝大家早日进入大厂,拿到满意的薪资和职级~~~加油!!

感谢大家的支持!!

[外链图片转存中…(img-sWGo6STx-1631174255313)]

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐