淺析Java方法反射原理

1. 前言

1.1 目標

java程序員日常開發經常使用到反射技術,所以本文就是要講解一下java的方法反射,讓大家更好了解反射的性能.

1.2 反射性能結論

  • 默認配置下,前15次的反射方法會通過native方法執行,在native方法中,如本方法是熱點,是無法有效的內聯優化 ,而且在native方法中要檢查及組裝方法參數,最後動態執行,也進一步影響性能 。
  • 默認配置下,超過15次後,會通過字節碼生成對應代理類,間接調用目標方法.這種實現方式可接近直接調用方法的性能,缺點使用字節碼生成代理類要耗性能及在運行時會多加載一個類

2. 代碼示例

2.1 示例代碼

public class ReflectionTest {
    public static int count =0;
    public void test(){
        new Exception((count++)+" : print stackTrace ").printStackTrace();
    }

    public static void main(String[] args) throws Exception {
        ReflectionTest test = new ReflectionTest();
        Method method = test.getClass().getMethod("test");
        for(int i=0;i<20;i++){
           method.invoke(test);
        }
    }
}

2.2 打印結果

...
java.lang.Exception: 14 : print stackTrace 
	at reflection1.ReflectionTest.test(ReflectionTest.java:8)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at reflection1.ReflectionTest.main(ReflectionTest.java:15)
java.lang.Exception: 15 : print stackTrace 
	at reflection1.ReflectionTest.test(ReflectionTest.java:8)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at reflection1.ReflectionTest.main(ReflectionTest.java:15)
java.lang.Exception: 16 : print stackTrace 
	at reflection1.ReflectionTest.test(ReflectionTest.java:8)
	at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at reflection1.ReflectionTest.main(ReflectionTest.java:15)

注意 第11行與第18行的棧調用鏈是不同的,11行的invoke還是NativeMethodAccessorImpl實現的,而18行是通過GeneratedMethodAccessor1實現的

3. 流程概要分析

3.1 概要流程

在這裏插入圖片描述

3.1.1 設置-Dsun.reflect.noInflation=true

如果啓動參數設置了-Dsun.reflect.noInflation=true則每次調用method.invoke()都會生成代理類,並間接調用目標方法
jvm默認的設置爲-Dsun.reflect.noInflation=false

3.1.2 調用native方法實現反射

如果method.invoke()執行次數<=15次(具體多少次可由sun.reflect.inflationThreshold決定,默認是15次)
從2.2的打印結果中可以從棧信息中看出:
前15次都是通過調用:sun.reflect.NativeMethodAccessorImpl.invoke0這個方法實現反射的,其代碼如下:

private static native Object invoke0(Method m, Object obj, Object[] args);

從聲明上可以看出是個本地方法,具體在代碼分析階段會分析到

3.1.3 生成代理類,間接調用ReflectionTest.test方法

如果method.invoke()執行次數>15次,則與設置了sun.reflect.noInflation=true一樣,會通過字節碼生成代理類,通過代理類間接調用目標方法.
其調用鏈條爲: Method.invoke()->DelegatingMethodAccessorImpl.invoke()->GeneratedMethodAccessor1.invoke() ->目標方法

具體查看所生成的代理類的方法如下:

  • debug 方式啓動目標類
  • 啓動HSDB
  • attach 到目標進程上
  • 在HSDB上 Class Browser上查找到GeneratedMethodAccessor1類,並點擊:Create .class File 這連接
    在這裏插入圖片描述
  • 在本地用戶 下的sun/reflect/目錄下可以找到GeneratedMethodAccessor1.class,並將其反編譯一下,如果如下:
package sun.reflect;
import java.lang.reflect.InvocationTargetException;
public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
    public Object invoke(Object var1, Object[] var2) throws InvocationTargetException {
        if (var1 == null) {
            throw new NullPointerException();
        } else {
            ReflectionTest var10000;
            try {
                var10000 = (ReflectionTest)var1;
                if (var2 != null && var2.length != 0) {
                    throw new IllegalArgumentException();
                }
            } catch (NullPointerException | ClassCastException var4) {
                throw new IllegalArgumentException(var4.toString());
            }

            try {
                var10000.test();
                return null;
            } catch (Throwable var3) {
                throw new InvocationTargetException(var3);
            }
        }
    }
    public GeneratedMethodAccessor1() {
    }
}

4. 代碼分析

4.1 Method.invoke()方法 分析

反射的主要邏輯是如果MethodAccessor對象爲空,則通過acquireMethodAccessor()創建一個.
然後調用MethodAccessor對象的invoke()方法實現反射調用.

public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
        MethodAccessor ma = methodAccessor; 
        if (ma == null) {
            ma = acquireMethodAccessor();//見:4.1.1.acquireMethodAccessor方法
        }
        return ma.invoke(obj, args); 
    }

4.1.1 Method.acquireMethodAccessor方法

MethodAccessor對象主要由reflectionFactory.newMethodAccessor(this)實現

    private MethodAccessor acquireMethodAccessor() {
        // First check to see if one has been created yet, and take it
        // if so
        MethodAccessor tmp = null;
        if (root != null) tmp = root.getMethodAccessor();//最開始是空
        if (tmp != null) {
            methodAccessor = tmp;
        } else {
            // Otherwise fabricate one and propagate it up to the root
            tmp = reflectionFactory.newMethodAccessor(this);//創建methodAccessor對象,見 4.1.2 newMethodAccessor方法
            setMethodAccessor(tmp);
        }
        return tmp;
    }

4.1.2 ReflectionFactory.newMethodAccessor

當sun.reflect.noInflation=false時,會創建出MethodAccessor的實現類DelegatingMethodAccessorImpl,
Method.invoke()方法主要調用的是DelegatingMethodAccessorImpl的invoke()方法.
而DelegatingMethodAccessorImpl的invoke()方法執行的其delegate.invoke()方法
在當前的方法中delegate指向的是NativeMethodAccessorImpl對象
NativeMethodAccessorImpl類的invoke實現可見 4.1.3 NativeMethodAccessorImpl.invoke

    public MethodAccessor newMethodAccessor(Method method) {
        checkInitted();

        if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {//設置-Dsun.reflect.noInflation=true纔會執行
            return new MethodAccessorGenerator().
                generateMethod(method.getDeclaringClass(),
                               method.getName(),
                               method.getParameterTypes(),
                               method.getReturnType(),
                               method.getExceptionTypes(),
                               method.getModifiers());
        } else {
            NativeMethodAccessorImpl acc =
                new NativeMethodAccessorImpl(method);
            DelegatingMethodAccessorImpl res =
                new DelegatingMethodAccessorImpl(acc);//後面的invoke就是調用本類的
            acc.setParent(res);
            return res;
        }
    }

4.1.3 NativeMethodAccessorImpl.invoke

從代碼上可以看出,如果本方法重複執行大於15,則會將其父類即DelegatingMethodAccessorImpl的delegate類換成由MethodAccessorGenerator產生的字節碼

   public Object invoke(Object obj, Object[] args)
        throws IllegalArgumentException, InvocationTargetException
    {
        if (++numInvocations > ReflectionFactory.inflationThreshold() //默認15
                && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
            MethodAccessorImpl acc = (MethodAccessorImpl)
                new MethodAccessorGenerator().
                    generateMethod(method.getDeclaringClass(),
                                   method.getName(),
                                   method.getParameterTypes(),
                                   method.getReturnType(),
                                   method.getExceptionTypes(),
                                   method.getModifiers());
            parent.setDelegate(acc);
        }
        return invoke0(method, obj, args);//本地類
    }

4.2 NativeMethodAccessorImpl.invoke0方法

NativeMethodAccessorImpl.invoke0方法是本地方法,按java jni的習慣規則,我們可以在/jdk/src/share/native/sun/reflect/目錄下找到NativeAccessors.c,再根據:"包名_類名_方法名"規則找到方法,其代碼實現如下:

JNIEXPORT jobject JNICALL Java_sun_reflect_NativeMethodAccessorImpl_invoke0
(JNIEnv *env, jclass unused, jobject m, jobject obj, jobjectArray args)
{
    return JVM_InvokeMethod(env, m, obj, args);
}

然後調用 jvm.cpp的下面方法

JVM_ENTRY(jobject, JVM_InvokeMethod(JNIEnv *env, jobject method, jobject obj, jobjectArray args0))
  JVMWrapper("JVM_InvokeMethod");
  Handle method_handle;
  if (thread->stack_available((address) &method_handle) >= JVMInvokeMethodSlack) {
    method_handle = Handle(THREAD, JNIHandles::resolve(method));
    Handle receiver(THREAD, JNIHandles::resolve(obj));
    objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0)));
    //反射調用主要是調用下面方法實現的
    oop result = Reflection::invoke_method(method_handle(), receiver, args, CHECK_NULL);
    jobject res = JNIHandles::make_local(env, result);
    if (JvmtiExport::should_post_vm_object_alloc()) {
      oop ret_type = java_lang_reflect_Method::return_type(method_handle());
      assert(ret_type != NULL, "sanity check: ret_type oop must not be NULL!");
      if (java_lang_Class::is_primitive(ret_type)) {
        JvmtiExport::post_vm_object_alloc(JavaThread::current(), result);
      }
    }
    return res;
  } else {
    THROW_0(vmSymbols::java_lang_StackOverflowError());
  }
JVM_END

4.2.1 Reflection::invoke_method

reflection.cpp的invoke_method方法

oop Reflection::invoke_method(oop method_mirror, Handle receiver, objArrayHandle args, TRAPS) {
  oop mirror             = java_lang_reflect_Method::clazz(method_mirror);
  int slot               = java_lang_reflect_Method::slot(method_mirror);
  bool override          = java_lang_reflect_Method::override(method_mirror) != 0;
  objArrayHandle ptypes(THREAD, objArrayOop(java_lang_reflect_Method::parameter_types(method_mirror)));
  oop return_type_mirror = java_lang_reflect_Method::return_type(method_mirror);
  BasicType rtype;
  if (java_lang_Class::is_primitive(return_type_mirror)) {
    rtype = basic_type_mirror_to_basic_type(return_type_mirror, CHECK_NULL);
  } else {
    rtype = T_OBJECT;
  }
  instanceKlassHandle klass(THREAD, java_lang_Class::as_Klass(mirror));
  //取得Method對象
  Method* m = klass->method_with_idnum(slot);
  if (m == NULL) {
    THROW_MSG_0(vmSymbols::java_lang_InternalError(), "invoke");
  }
  methodHandle method(THREAD, m);
  //主要的邏輯在invoke方法
  return invoke(klass, method, receiver, override, ptypes, rtype, args, true, THREAD);
}

4.2.1 Reflection::invoke

oop Reflection::invoke(instanceKlassHandle klass, methodHandle reflected_method,
                       Handle receiver, bool override, objArrayHandle ptypes,
                       BasicType rtype, objArrayHandle args, bool is_method_invoke, TRAPS) {
  ResourceMark rm(THREAD);

  methodHandle method;      // actual method to invoke
  KlassHandle target_klass; // target klass, receiver's klass for non-static

  // Ensure klass is initialized
  klass->initialize(CHECK_NULL);

  bool is_static = reflected_method->is_static();
  if (is_static) {
    // ignore receiver argument
    method = reflected_method;
    target_klass = klass;
  } else {
    // check for null receiver
    if (receiver.is_null()) {
      THROW_0(vmSymbols::java_lang_NullPointerException());
    }
    // Check class of receiver against class declaring method
    if (!receiver->is_a(klass())) {
      THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "object is not an instance of declaring class");
    }
    // target klass is receiver's klass
    target_klass = KlassHandle(THREAD, receiver->klass());
    // no need to resolve if method is private or <init>
    if (reflected_method->is_private() || reflected_method->name() == vmSymbols::object_initializer_name()) {
      method = reflected_method;
    } else {
      //如果是接口方法,則執行如下邏輯
      if (reflected_method->method_holder()->is_interface()) {
        // resolve interface call
        if (ReflectionWrapResolutionErrors) {
          method = resolve_interface_call(klass, reflected_method, target_klass, receiver, THREAD);
          if (HAS_PENDING_EXCEPTION) {
            oop resolution_exception = PENDING_EXCEPTION;
            CLEAR_PENDING_EXCEPTION;
            JavaCallArguments args(Handle(THREAD, resolution_exception));
            THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
                vmSymbols::throwable_void_signature(),
                &args);
          }
        } else {
          method = resolve_interface_call(klass, reflected_method, target_klass, receiver, CHECK_(NULL));
        }
      }  else {
        //否則通過查詢虛方法表vtable來確定最終的方法
        assert(!reflected_method->has_itable_index(), "");
        int index = reflected_method->vtable_index();
        method = reflected_method;
        if (index != Method::nonvirtual_vtable_index) {
          InstanceKlass* inst = (InstanceKlass*)target_klass();
          method = methodHandle(THREAD, inst->method_at_vtable(index));
        }
        if (!method.is_null()) {
          // Check for abstract methods as well
          if (method->is_abstract()) {
            // new default: 6531596
            if (ReflectionWrapResolutionErrors) {
              ResourceMark rm(THREAD);
              Handle h_origexception = Exceptions::new_exception(THREAD,
                     vmSymbols::java_lang_AbstractMethodError(),
                     Method::name_and_sig_as_C_string(target_klass(),
                     method->name(),
                     method->signature()));
              JavaCallArguments args(h_origexception);
              THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
                vmSymbols::throwable_void_signature(),
                &args);
            } else {
              ResourceMark rm(THREAD);
              THROW_MSG_0(vmSymbols::java_lang_AbstractMethodError(),
                        Method::name_and_sig_as_C_string(target_klass(),
                                                                method->name(),
                                                                method->signature()));
            }
          }
        }
      }
    }
  }
  if (method.is_null()) {
    ResourceMark rm(THREAD);
    THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(),
                Method::name_and_sig_as_C_string(klass(),
                                                        reflected_method->name(),
                                                        reflected_method->signature()));
  }
  if (!(JDK_Version::is_gte_jdk14x_version() && UseNewReflection)) {

  if (!override) {
    if (!(klass->is_public() && reflected_method->is_public())) {
      bool access = Reflection::reflect_check_access(klass(), reflected_method->access_flags(), target_klass(), is_method_invoke, CHECK_NULL);
      if (!access) {
        return NULL; // exception
      }
    }
  }

  } // !(Universe::is_gte_jdk14x_version() && UseNewReflection)

  assert(ptypes->is_objArray(), "just checking");
  int args_len = args.is_null() ? 0 : args->length();
  // Check number of arguments
  if (ptypes->length() != args_len) {
    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "wrong number of arguments");
  }

  // Create object to contain parameters for the JavaCall
  JavaCallArguments java_args(method->size_of_parameters());

  if (!is_static) {
    java_args.push_oop(receiver);
  }
//如果反射的方法有參加,則把參數加入到java_args中
  for (int i = 0; i < args_len; i++) {
    oop type_mirror = ptypes->obj_at(i);
    oop arg = args->obj_at(i);
    //如果是基本類型,按如下處理
    if (java_lang_Class::is_primitive(type_mirror)) {
      jvalue value;
      BasicType ptype = basic_type_mirror_to_basic_type(type_mirror, CHECK_NULL);
      BasicType atype = unbox_for_primitive(arg, &value, CHECK_NULL);
      if (ptype != atype) {
        widen(&value, atype, ptype, CHECK_NULL);
      }
      switch (ptype) {
        case T_BOOLEAN:     java_args.push_int(value.z);    break;
        case T_CHAR:        java_args.push_int(value.c);    break;
        case T_BYTE:        java_args.push_int(value.b);    break;
        case T_SHORT:       java_args.push_int(value.s);    break;
        case T_INT:         java_args.push_int(value.i);    break;
        case T_LONG:        java_args.push_long(value.j);   break;
        case T_FLOAT:       java_args.push_float(value.f);  break;
        case T_DOUBLE:      java_args.push_double(value.d); break;
        default:
          THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
      }
    } else {
      if (arg != NULL) {
        Klass* k = java_lang_Class::as_Klass(type_mirror);
        if (!arg->is_a(k)) {
          THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
        }
      }
      Handle arg_handle(THREAD, arg);         // Create handle for argument
      java_args.push_oop(arg_handle); // Push handle
    }
  }

  assert(java_args.size_of_parameters() == method->size_of_parameters(), "just checking");

  JavaValue result(rtype);
  //最終調用JavaCalls::call執行
  JavaCalls::call(&result, method, &java_args, THREAD);

  if (HAS_PENDING_EXCEPTION) {
    // Method threw an exception; wrap it in an InvocationTargetException
    oop target_exception = PENDING_EXCEPTION;
    CLEAR_PENDING_EXCEPTION;
    JavaCallArguments args(Handle(THREAD, target_exception));
    THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
                vmSymbols::throwable_void_signature(),
                &args);
  } else {
    if (rtype == T_BOOLEAN || rtype == T_BYTE || rtype == T_CHAR || rtype == T_SHORT)
      narrow((jvalue*) result.get_value_addr(), rtype, CHECK_NULL);
    return box((jvalue*) result.get_value_addr(), rtype, CHECK_NULL);
  }
}

作者: 吳煉鈿

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