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面试题解析+核心总结学习笔记+最新讲解视频】](
)**
祝大家早日进入大厂,拿到满意的薪资和职级~~~加油!!
感谢大家的支持!!
ClassFileStream* stream = new ClassFileStream(ptr,
end_ptr - ptr,
pathname,
ClassFileStream::verify);
最后
这份清华大牛整理的进大厂必备的redis视频、面试题和技术文档
**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](
)**
祝大家早日进入大厂,拿到满意的薪资和职级~~~加油!!
感谢大家的支持!!
[外链图片转存中…(img-sWGo6STx-1631174255313)]
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。