java反射之Method的invoke方法实现

https://blog.csdn.net/wenyuan65/article/details/81145900

在框架中经常会会用到method.invoke()方法,用来执行某个的对象的目标方法。以前写代码用到反射时,总是获取先获取Method,然后传入对应的Class实例对象执行方法。然而前段时间研究invoke方法时,发现invoke方法居然包含多态的特性,这是以前没有考虑过的一个问题。那么Method.invoke()方法的执行过程是怎么实现的?它的多态又是如何实现的呢?

本文将从java和JVM的源码实现深入探讨invoke方法的实现过程。

首先给出invoke方法多态特性的演示代码:

  1.  
    public class MethodInvoke {
  2.  
     
  3.  
    public static void main(String[] args) throws Exception {
  4.  
    Method animalMethod = Animal.class.getDeclaredMethod("print");
  5.  
    Method catMethod = Cat.class.getDeclaredMethod("print");
  6.  
     
  7.  
    Animal animal = new Animal();
  8.  
    Cat cat = new Cat();
  9.  
    animalMethod.invoke(cat);
  10.  
    animalMethod.invoke(animal);
  11.  
     
  12.  
    catMethod.invoke(cat);
  13.  
    catMethod.invoke(animal);
  14.  
    }
  15.  
     
  16.  
    }
  17.  
     
  18.  
    class Animal {
  19.  
     
  20.  
    public void print() {
  21.  
    System.out.println("Animal.print()");
  22.  
    }
  23.  
     
  24.  
    }
  25.  
     
  26.  
    class Cat extends Animal {
  27.  
     
  28.  
    @Override
  29.  
    public void print() {
  30.  
    System.out.println("Cat.print()");
  31.  
    }
  32.  
     
  33.  
    }

代码中,Cat类覆盖了父类Animal的print()方法, 然后通过反射分别获取print()的Method对象。最后分别用Cat和Animal的实例对象去执行print()方法。其中animalMethod.invoke(animal)和catMethod.invoke(cat),示例对象的真实类型和Method的声明Classs是相同的,按照预期打印结果;animalMethod.invoke(cat)中,由于Cat是Animal的子类,按照多态的特性,子类调用父类的的方法,方法执行时会动态链接到子类的实现方法上。因此,这里会调用Cat.print()方法;而catMethod.invoke(animal)中,传入的参数类型Animal是父类,却期望调用子类Cat的方法,因此这一次会抛出异常。代码打印结果为:

  1.  
    Cat.print()
  2.  
    Animal.print()
  3.  
    Cat.print()
  4.  
    Exception in thread "main" java.lang.IllegalArgumentException: object is not an instance of declaring class
  5.  
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  6.  
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  7.  
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  8.  
    at java.lang.reflect.Method.invoke(Unknown Source)
  9.  
    at com.wy.invoke.MethodInvoke.main(MethodInvoke.java:17)

接下来,我们来看看invoke()方法的实现过程。

  1.  
    public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
  2.  
    {
  3.  
    if (!override) {
  4.  
    if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
  5.  
    Class<?> caller = Reflection.getCallerClass(1);
  6.  
     
  7.  
    checkAccess(caller, clazz, obj, modifiers);
  8.  
    }
  9.  
    }
  10.  
    MethodAccessor ma = methodAccessor; // read volatile
  11.  
    if (ma == null) {
  12.  
    ma = acquireMethodAccessor();
  13.  
    }
  14.  
    return ma.invoke(obj, args);
  15.  
    }

invoke()方法中主要分为两部分:访问控制检查和调用MethodAccessor.invoke()实现方法执行。

首先看一下访问控制检查这一块的逻辑。第一眼看到这里的逻辑的时候,很容易搞不清楚是干嘛的。通俗来讲就是通过方法的修饰符(public/protected/private/package),来判断方法的调用者是否可以访问该方法。这是java的基础内容,不过用代码写出来,一下子不容易想到。访问控制检查分为3步:

  1. 检查override,如果override为true,跳过检查;否则继续;
  2. 快速检查,判断该方法的修饰符modifiers是否为public,如果是跳过检查;否则继续;
  3. 详细检查,通过方法的(protected/private/package)修饰符或方法的声明类(例如子类可以访问父类的protected方法)与调用者caller之间的关系,判断caller是否有权限访问该方法。

override属性是Method的父类AccessibleObject中声明的变量,使得程序可以控制是否跳过访问权限的检查。另外,Method的实例对象中,override属性的初始值设置为false。

  1.  
    public void setAccessible(boolean flag) throws SecurityException {
  2.  
    SecurityManager sm = System.getSecurityManager();
  3.  
    if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
  4.  
    setAccessible0(this, flag);
  5.  
    }
  6.  
     
  7.  
    private static void setAccessible0(AccessibleObject obj, boolean flag)
  8.  
    throws SecurityException
  9.  
    {
  10.  
    if (obj instanceof Constructor && flag == true) {
  11.  
    Constructor<?> c = (Constructor<?>)obj;
  12.  
    if (c.getDeclaringClass() == Class.class) {
  13.  
    throw new SecurityException("Can not make a java.lang.Class" +
  14.  
    " constructor accessible");
  15.  
    }
  16.  
    }
  17.  
    obj.override = flag;
  18.  
    }

多说一句,Field同样继承了AccessibleObject,且Field的override也是初始化为false的,也就是说并没有按照变量的修饰符去初始化不同的值。但是我们在调用Field.set(Object obj, Object value)时,如果该Field是private修饰的,会因没有访问权限而抛出异常,因此必须调用setAccessible(true)。此处非常容易理解为因为变量是public的,所以override就被初始化为true。

invoke()方法中,访问控制检查之后,就是通过MethodAccessor.invoke()调用方法。再来看一下代码:

  1.  
    MethodAccessor ma = methodAccessor; // read volatile
  2.  
    if (ma == null) {
  3.  
    ma = acquireMethodAccessor();
  4.  
    }
  5.  
    return ma.invoke(obj, args);

这里的逻辑很简单,首先将变量methodAccessor赋值给ma,在方法栈中保存一个可以直接引用的本地变量,如果methodAccessor不存在,调用acquireMethodAccessor()方法创建一个。

  1.  
    private volatile MethodAccessor methodAccessor;
  2.  
    private Method root;
  3.  
     
  4.  
    private MethodAccessor acquireMethodAccessor() {
  5.  
    // First check to see if one has been created yet, and take it
  6.  
    // if so
  7.  
    MethodAccessor tmp = null;
  8.  
    if (root != null) tmp = root.getMethodAccessor();
  9.  
    if (tmp != null) {
  10.  
    methodAccessor = tmp;
  11.  
    } else {
  12.  
    // Otherwise fabricate one and propagate it up to the root
  13.  
    tmp = reflectionFactory.newMethodAccessor(this);
  14.  
    setMethodAccessor(tmp);
  15.  
    }
  16.  
     
  17.  
    return tmp;
  18.  
    }
  19.  
     
  20.  
    void setMethodAccessor(MethodAccessor accessor) {
  21.  
    methodAccessor = accessor;
  22.  
    // Propagate up
  23.  
    if (root != null) {
  24.  
    root.setMethodAccessor(accessor);
  25.  
    }
  26.  
    }
  27.  
     
  28.  
    Method copy() {
  29.  
    Method res = new Method(clazz, name, parameterTypes, returnType,
  30.  
    exceptionTypes, modifiers, slot, signature,
  31.  
    annotations, parameterAnnotations, annotationDefault);
  32.  
    res.root = this;
  33.  
    res.methodAccessor = methodAccessor;
  34.  
    return res;
  35.  
    }

综合acquireMethodAccessor(),setMethodAccessor()以及copy()这三个方法,可以看到一个Method实例对象维护了一个root引用。当调用Method.copy()进行方法拷贝时,root指向了被拷贝的对象。那么当一个Method被多次拷贝后,调用一次setMethodAccessor()方法,就会将root引用所指向的Method的methodAccessor变量同样赋值。例如:D -> C -> B -> A,其中X-> Y表示X = Y.copy(), 当C对象调用setMethodAccessor()时,B和A都会传播赋值methodAccessor, 而D的methodAccessor还是null。紧接着,当D需要获取methodAccessor而调用acquireMethodAccessor()时,D获取root的methodAccessor, 那么D将和ABC持有相同的methodAccessor。

虽然Method中,通过维护root引用意图使相同的方法始终保持只有一个methodAccessor实例,但是上述方法仍然无法保证相同的方法只有一个methodAccessor实例。例如通过copy()使ABCD保持关系:D -> C -> B -> A, 当B对象调用setMethodAccessor()时,B和A都会赋值methodAccessor, 而C、D的methodAccessor还是null。这时D调用acquireMethodAccessor()时,D获取root也就是C的methodAccessor,发现为空,然后就新创建了一个。从而出现了相同的方法中出现了两个methodAccessor实例对象的现象。

在Class.getMethod()、Class.getDeclaredMethod()以及Class.getDeclaredMethod(String name, Class<?>... parameterTypes)方法中最终都会调用copy()方法来保障Method使用的安全性。 在比较极端加巧合的情况下,可能会引起类膨胀的问题,这就是接下来要讲到的MethodAccessor的实现机制。

copy

在前面代码中,MethodAccessor的创建是通过反射工厂ReflectionFactory的newMethodAccessor(Method)方法来创建的。

  1.  
    public MethodAccessor newMethodAccessor(Method method) {
  2.  
    checkInitted();
  3.  
     
  4.  
    if (noInflation) {
  5.  
    return new MethodAccessorGenerator().
  6.  
    generateMethod(method.getDeclaringClass(),
  7.  
    method.getName(),
  8.  
    method.getParameterTypes(),
  9.  
    method.getReturnType(),
  10.  
    method.getExceptionTypes(),
  11.  
    method.getModifiers());
  12.  
    } else {
  13.  
    NativeMethodAccessorImpl acc =
  14.  
    new NativeMethodAccessorImpl(method);
  15.  
    DelegatingMethodAccessorImpl res =
  16.  
    new DelegatingMethodAccessorImpl(acc);
  17.  
    acc.setParent(res);
  18.  
    return res;
  19.  
    }
  20.  
    }

其中, checkInitted()方法检查从配置项中读取配置并设置noInflation、inflationThreshold的值:

  1.  
    private static void checkInitted() {
  2.  
    if (initted) return;
  3.  
    AccessController.doPrivileged(
  4.  
    new PrivilegedAction<Void>() {
  5.  
    public Void run() {
  6.  
     
  7.  
    if (System.out == null) {
  8.  
    // java.lang.System not yet fully initialized
  9.  
    return null;
  10.  
    }
  11.  
     
  12.  
    String val = System.getProperty("sun.reflect.noInflation");
  13.  
    if (val != null && val.equals("true")) {
  14.  
    noInflation = true;
  15.  
    }
  16.  
     
  17.  
    val = System.getProperty("sun.reflect.inflationThreshold");
  18.  
    if (val != null) {
  19.  
    try {
  20.  
    inflationThreshold = Integer.parseInt(val);
  21.  
    } catch (NumberFormatException e) {
  22.  
    throw (RuntimeException)
  23.  
    new RuntimeException("Unable to parse property sun.reflect.inflationThreshold").
  24.  
    initCause(e);
  25.  
    }
  26.  
    }
  27.  
     
  28.  
    initted = true;
  29.  
    return null;
  30.  
    }
  31.  
    });
  32.  
    }

可以通过启动参数-Dsun.reflect.noInflation=false -Dsun.reflect.inflationThreshold=15来设置:

结合字面意思及下面代码理解,这两个配置sun.reflect.noInflation是控制是否立即进行类膨胀,sun.reflect.inflationThreshold是设置类膨胀阈值。

创建MethodAccessor有两种选择,一种是当sun.reflect.noInflation配置项为true时,ReflectionFactory利用MethodAccessor的字节码生成类 MethodAccessorGenerator直接创建一个代理类,通过间接调用原方法完成invoke()任务,具体实现稍后给出。MethodAccessor的另一种实现方式是,创建DelegatingMethodAccessorImpl 委托类,并将执行invoke()方法的具体内容交由NativeMethodAccessorImpl实现,而NativeMethodAccessorImpl最终调用native方法完成invoke()任务。以下是NativeMethodAccessorImpl的invoke()方法实现。

  1.  
    public Object invoke(Object obj, Object[] args)
  2.  
    throws IllegalArgumentException, InvocationTargetException
  3.  
    {
  4.  
    if (++numInvocations > ReflectionFactory.inflationThreshold()) {
  5.  
    MethodAccessorImpl acc = (MethodAccessorImpl)
  6.  
    new MethodAccessorGenerator().
  7.  
    generateMethod(method.getDeclaringClass(),
  8.  
    method.getName(),
  9.  
    method.getParameterTypes(),
  10.  
    method.getReturnType(),
  11.  
    method.getExceptionTypes(),
  12.  
    method.getModifiers());
  13.  
    parent.setDelegate(acc);
  14.  
    }
  15.  
     
  16.  
    return invoke0(method, obj, args);
  17.  
    }
  18.  
     
  19.  
    private static native Object invoke0(Method m, Object obj, Object[] args);

可以看到,当numInvocations数量大于配置项sun.reflect.inflationThreshold即类膨胀阈值时, 使用MethodAccessorGenerator创建一个代理类对象,并且将被委托的NativeMethodAccessorImpl的parent,也就是委托类DelegatingMethodAccessorImpl的委托类设置为这个生成的代理对象。这么说可能有点绕,下面用一幅图表示这个过程。

delegate

总体来说,当调用invoke()时,按照默认配置,Method首先创建一个DelegatingMethodAccessorImpl对象,并设置一个被委托的NativeMethodAccessorImpl对象,那么method.invoke()就被转换成DelegatingMethodAccessorImpl.invoke(),然后又被委托给NativeMethodAccessorImp.invoke()实现。当NativeMethodAccessorImp.invoke()调用次数超过一定热度时(默认15次),被委托方又被转换成代理类来实现。

之前提到过在极端情况下,同一个方法的Method对象存在多个不同拷贝拷贝时,可能存在多个MethodAccessor对象。那么当多次调用后,必然会生成两个重复功能的代理类。当然,一般情况下,生成两个代理类并没有较大的影响。

其中代理类的具体字节码实现过程较为复杂,大体思想是生成一个如下所示的类:

  1.  
    public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
  2.  
     
  3.  
    public GeneratedMethodAccessor1 () {
  4.  
    super();
  5.  
    }
  6.  
     
  7.  
    public Object invoke(Object obj, Object[] args)
  8.  
    throws IllegalArgumentException, InvocationTargetException
  9.  
    {
  10.  
    if (!(obj instanceof Cat)) {
  11.  
    throw new ClassCastException();
  12.  
    }
  13.  
    if (args != null && args.length != 0) {
  14.  
    throw new IllegalArgumentException();
  15.  
    }
  16.  
     
  17.  
    try {
  18.  
    Cat cat = (Cat) obj;
  19.  
    cat.print();
  20.  
    return null;
  21.  
    } catch (Throwable e) {
  22.  
    throw new InvocationTargetException(e, "invoke error");
  23.  
    }
  24.  
    }
  25.  
     
  26.  
    }

到目前为止,除了在代理的GeneratedMethodAccessor1 类中,方法的执行有多态的特性,而NativeMethodAccessorImp的invoke()实现是在jdk中的完成的。接下来我们将目光移到NativeMethodAccessorImp的native方法invoke0();

openJDK下载地址

首先,在\jdk\src\share\native\sun\reflect路径下找到NativeAccessors.c, 其中有Java_sun_reflect_NativeMethodAccessorImpl _invoke0()方法,根据JNI定义函数名的规则"包名_类名_方法名",这就是我们要找的native方法实现入口。

  1.  
    JNIEXPORT jobject JNICALL Java_sun_reflect_NativeMethodAccessorImpl_invoke0
  2.  
    (JNIEnv *env, jclass unused, jobject m, jobject obj, jobjectArray args)
  3.  
    {
  4.  
    return JVM_InvokeMethod(env, m, obj, args);
  5.  
    }

方法调用JVM_InvokeMethod(), 一般以JVM_开头的函数定义在jvm.cpp文件中,不熟悉的话可以通过头文件jvm.h看出来。继续追踪,发现jvm.cpp文件位于spot\src\share\vm\prims文件夹下。

  1.  
    JVM_ENTRY(jobject, JVM_InvokeMethod(JNIEnv *env, jobject method, jobject obj, jobjectArray args0))
  2.  
    JVMWrapper("JVM_InvokeMethod");
  3.  
    Handle method_handle;
  4.  
    if (thread->stack_available((address) &method_handle) >= JVMInvokeMethodSlack) {
  5.  
    method_handle = Handle(THREAD, JNIHandles::resolve(method));
  6.  
    Handle receiver(THREAD, JNIHandles::resolve(obj));
  7.  
    objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0)));
  8.  
    oop result = Reflection::invoke_method(method_handle(), receiver, args, CHECK_NULL);
  9.  
    jobject res = JNIHandles::make_local(env, result);
  10.  
    if (JvmtiExport::should_post_vm_object_alloc()) {
  11.  
    oop ret_type = java_lang_reflect_Method::return_type(method_handle());
  12.  
    assert(ret_type != NULL, "sanity check: ret_type oop must not be NULL!");
  13.  
    if (java_lang_Class::is_primitive(ret_type)) {
  14.  
    // Only for primitive type vm allocates memory for java object.
  15.  
    // See box() method.
  16.  
    JvmtiExport::post_vm_object_alloc(JavaThread::current(), result);
  17.  
    }
  18.  
    }
  19.  
    return res;
  20.  
    } else {
  21.  
    THROW_0(vmSymbols::java_lang_StackOverflowError());
  22.  
    }
  23.  
    JVM_END

其中oop result = Reflection::invoke_method(method_handle(), receiver, args, CHECK_NULL)是方法的执行过程,在\hotspot\src\share\vm\runtime路径下找到reflection.cpp文件。

  1.  
    oop Reflection::invoke_method(oop method_mirror, Handle receiver, objArrayHandle args, TRAPS) {
  2.  
    oop mirror = java_lang_reflect_Method::clazz(method_mirror);
  3.  
    int slot = java_lang_reflect_Method::slot(method_mirror);
  4.  
    bool override = java_lang_reflect_Method::override(method_mirror) != 0;
  5.  
    objArrayHandle ptypes(THREAD, objArrayOop(java_lang_reflect_Method::parameter_types(method_mirror)));
  6.  
     
  7.  
    oop return_type_mirror = java_lang_reflect_Method::return_type(method_mirror);
  8.  
    BasicType rtype;
  9.  
    if (java_lang_Class::is_primitive(return_type_mirror)) {
  10.  
    rtype = basic_type_mirror_to_basic_type(return_type_mirror, CHECK_NULL);
  11.  
    } else {
  12.  
    rtype = T_OBJECT;
  13.  
    }
  14.  
     
  15.  
    instanceKlassHandle klass(THREAD, java_lang_Class::as_Klass(mirror));
  16.  
    Method* m = klass->method_with_idnum(slot);
  17.  
    if (m == NULL) {
  18.  
    THROW_MSG_0(vmSymbols::java_lang_InternalError(), "invoke");
  19.  
    }
  20.  
    methodHandle method(THREAD, m);
  21.  
     
  22.  
    return invoke(klass, method, receiver, override, ptypes, rtype, args, true, THREAD);
  23.  
    }
  24.  
     
  25.  
    oop Reflection::invoke(instanceKlassHandle klass, methodHandle reflected_method,
  26.  
    Handle receiver, bool override, objArrayHandle ptypes,
  27.  
    BasicType rtype, objArrayHandle args, bool is_method_invoke, TRAPS) {
  28.  
    ResourceMark rm(THREAD);
  29.  
     
  30.  
    methodHandle method; // actual method to invoke
  31.  
    KlassHandle target_klass; // target klass, receiver's klass for non-static
  32.  
     
  33.  
    // Ensure klass is initialized
  34.  
    klass->initialize(CHECK_NULL);
  35.  
     
  36.  
    bool is_static = reflected_method->is_static();
  37.  
    if (is_static) {
  38.  
    // ignore receiver argument
  39.  
    method = reflected_method;
  40.  
    target_klass = klass;
  41.  
    } else {
  42.  
    // check for null receiver
  43.  
    if (receiver.is_null()) {
  44.  
    THROW_0(vmSymbols::java_lang_NullPointerException());
  45.  
    }
  46.  
    // Check class of receiver against class declaring method
  47.  
    if (!receiver->is_a(klass())) {
  48.  
    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "object is not an instance of declaring class");
  49.  
    }
  50.  
    // target klass is receiver's klass
  51.  
    target_klass = KlassHandle(THREAD, receiver->klass());
  52.  
    // no need to resolve if method is private or <init>
  53.  
    if (reflected_method->is_private() || reflected_method->name() == vmSymbols::object_initializer_name()) {
  54.  
    method = reflected_method;
  55.  
    } else {
  56.  
    // resolve based on the receiver
  57.  
    if (reflected_method->method_holder()->is_interface()) {
  58.  
    // resolve interface call
  59.  
    if (ReflectionWrapResolutionErrors) {
  60.  
    // new default: 6531596
  61.  
    // Match resolution errors with those thrown due to reflection inlining
  62.  
    // Linktime resolution & IllegalAccessCheck already done by Class.getMethod()
  63.  
    method = resolve_interface_call(klass, reflected_method, target_klass, receiver, THREAD);
  64.  
    if (HAS_PENDING_EXCEPTION) {
  65.  
    // Method resolution threw an exception; wrap it in an InvocationTargetException
  66.  
    oop resolution_exception = PENDING_EXCEPTION;
  67.  
    CLEAR_PENDING_EXCEPTION;
  68.  
    JavaCallArguments args(Handle(THREAD, resolution_exception));
  69.  
    THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
  70.  
    vmSymbols::throwable_void_signature(),
  71.  
    &args);
  72.  
    }
  73.  
    } else {
  74.  
    method = resolve_interface_call(klass, reflected_method, target_klass, receiver, CHECK_(NULL));
  75.  
    }
  76.  
    } else {
  77.  
    // if the method can be overridden, we resolve using the vtable index.
  78.  
    assert(!reflected_method->has_itable_index(), "");
  79.  
    int index = reflected_method->vtable_index();
  80.  
    method = reflected_method;
  81.  
    if (index != Method::nonvirtual_vtable_index) {
  82.  
    // target_klass might be an arrayKlassOop but all vtables start at
  83.  
    // the same place. The cast is to avoid virtual call and assertion.
  84.  
    InstanceKlass* inst = (InstanceKlass*)target_klass();
  85.  
    method = methodHandle(THREAD, inst->method_at_vtable(index));
  86.  
    }
  87.  
    if (!method.is_null()) {
  88.  
    // Check for abstract methods as well
  89.  
    if (method->is_abstract()) {
  90.  
    // new default: 6531596
  91.  
    if (ReflectionWrapResolutionErrors) {
  92.  
    ResourceMark rm(THREAD);
  93.  
    Handle h_origexception = Exceptions::new_exception(THREAD,
  94.  
    vmSymbols::java_lang_AbstractMethodError(),
  95.  
    Method::name_and_sig_as_C_string(target_klass(),
  96.  
    method->name(),
  97.  
    method->signature()));
  98.  
    JavaCallArguments args(h_origexception);
  99.  
    THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
  100.  
    vmSymbols::throwable_void_signature(),
  101.  
    &args);
  102.  
    } else {
  103.  
    ResourceMark rm(THREAD);
  104.  
    THROW_MSG_0(vmSymbols::java_lang_AbstractMethodError(),
  105.  
    Method::name_and_sig_as_C_string(target_klass(),
  106.  
    method->name(),
  107.  
    method->signature()));
  108.  
    }
  109.  
    }
  110.  
    }
  111.  
    }
  112.  
    }
  113.  
    }
  114.  
     
  115.  
    // I believe this is a ShouldNotGetHere case which requires
  116.  
    // an internal vtable bug. If you ever get this please let Karen know.
  117.  
    if (method.is_null()) {
  118.  
    ResourceMark rm(THREAD);
  119.  
    THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(),
  120.  
    Method::name_and_sig_as_C_string(klass(),
  121.  
    reflected_method->name(),
  122.  
    reflected_method->signature()));
  123.  
    }
  124.  
     
  125.  
    // In the JDK 1.4 reflection implementation, the security check is
  126.  
    // done at the Java level
  127.  
    if (!(JDK_Version::is_gte_jdk14x_version() && UseNewReflection)) {
  128.  
     
  129.  
    // Access checking (unless overridden by Method)
  130.  
    if (!override) {
  131.  
    if (!(klass->is_public() && reflected_method->is_public())) {
  132.  
    bool access = Reflection::reflect_check_access(klass(), reflected_method->access_flags(), target_klass(), is_method_invoke, CHECK_NULL);
  133.  
    if (!access) {
  134.  
    return NULL; // exception
  135.  
    }
  136.  
    }
  137.  
    }
  138.  
     
  139.  
    } // !(Universe::is_gte_jdk14x_version() && UseNewReflection)
  140.  
     
  141.  
    assert(ptypes->is_objArray(), "just checking");
  142.  
    int args_len = args.is_null() ? 0 : args->length();
  143.  
    // Check number of arguments
  144.  
    if (ptypes->length() != args_len) {
  145.  
    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "wrong number of arguments");
  146.  
    }
  147.  
     
  148.  
    // Create object to contain parameters for the JavaCall
  149.  
    JavaCallArguments java_args(method->size_of_parameters());
  150.  
     
  151.  
    if (!is_static) {
  152.  
    java_args.push_oop(receiver);
  153.  
    }
  154.  
     
  155.  
    for (int i = 0; i < args_len; i++) {
  156.  
    oop type_mirror = ptypes->obj_at(i);
  157.  
    oop arg = args->obj_at(i);
  158.  
    if (java_lang_Class::is_primitive(type_mirror)) {
  159.  
    jvalue value;
  160.  
    BasicType ptype = basic_type_mirror_to_basic_type(type_mirror, CHECK_NULL);
  161.  
    BasicType atype = unbox_for_primitive(arg, &value, CHECK_NULL);
  162.  
    if (ptype != atype) {
  163.  
    widen(&value, atype, ptype, CHECK_NULL);
  164.  
    }
  165.  
    switch (ptype) {
  166.  
    case T_BOOLEAN: java_args.push_int(value.z); break;
  167.  
    case T_CHAR: java_args.push_int(value.c); break;
  168.  
    case T_BYTE: java_args.push_int(value.b); break;
  169.  
    case T_SHORT: java_args.push_int(value.s); break;
  170.  
    case T_INT: java_args.push_int(value.i); break;
  171.  
    case T_LONG: java_args.push_long(value.j); break;
  172.  
    case T_FLOAT: java_args.push_float(value.f); break;
  173.  
    case T_DOUBLE: java_args.push_double(value.d); break;
  174.  
    default:
  175.  
    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
  176.  
    }
  177.  
    } else {
  178.  
    if (arg != NULL) {
  179.  
    Klass* k = java_lang_Class::as_Klass(type_mirror);
  180.  
    if (!arg->is_a(k)) {
  181.  
    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
  182.  
    }
  183.  
    }
  184.  
    Handle arg_handle(THREAD, arg); // Create handle for argument
  185.  
    java_args.push_oop(arg_handle); // Push handle
  186.  
    }
  187.  
    }
  188.  
     
  189.  
    assert(java_args.size_of_parameters() == method->size_of_parameters(), "just checking");
  190.  
     
  191.  
    // All oops (including receiver) is passed in as Handles. An potential oop is returned as an
  192.  
    // oop (i.e., NOT as an handle)
  193.  
    JavaValue result(rtype);
  194.  
    JavaCalls::call(&result, method, &java_args, THREAD);
  195.  
     
  196.  
    if (HAS_PENDING_EXCEPTION) {
  197.  
    // Method threw an exception; wrap it in an InvocationTargetException
  198.  
    oop target_exception = PENDING_EXCEPTION;
  199.  
    CLEAR_PENDING_EXCEPTION;
  200.  
    JavaCallArguments args(Handle(THREAD, target_exception));
  201.  
    THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
  202.  
    vmSymbols::throwable_void_signature(),
  203.  
    &args);
  204.  
    } else {
  205.  
    if (rtype == T_BOOLEAN || rtype == T_BYTE || rtype == T_CHAR || rtype == T_SHORT)
  206.  
    narrow((jvalue*) result.get_value_addr(), rtype, CHECK_NULL);
  207.  
    return box((jvalue*) result.get_value_addr(), rtype, CHECK_NULL);
  208.  
    }
  209.  
    }

Reflection::invoke_method()中调用Reflection::invoke(),然后在Reflection::invoke()方法中,当反射调用的方法是接口方法时,调用Reflection::resolve_interface_call(),该方法依赖LinkResolver::resolve_interface_call()来完成方法的动态链接过程,具体实现就不在这里展示。

method = resolve_interface_call(klass, reflected_method, target_klass, receiver, CHECK_(NULL));
  1.  
    methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, methodHandle method,
  2.  
    KlassHandle recv_klass, Handle receiver, TRAPS) {
  3.  
    assert(!method.is_null() , "method should not be null");
  4.  
     
  5.  
    CallInfo info;
  6.  
    Symbol* signature = method->signature();
  7.  
    Symbol* name = method->name();
  8.  
    LinkResolver::resolve_interface_call(info, receiver, recv_klass, klass,
  9.  
    name, signature,
  10.  
    KlassHandle(), false, true,
  11.  
    CHECK_(methodHandle()));
  12.  
    return info.selected_method();
  13.  
    }

如果反射调用的方法是可以被覆盖的方法,例如Animal.print(), Reflection::invoke()最终通过查询虚方法表vtable来确定最终的method。

  1.  
    // if the method can be overridden, we resolve using the vtable index.
  2.  
    assert(!reflected_method->has_itable_index(), "");
  3.  
    int index = reflected_method->vtable_index();
  4.  
    method = reflected_method;
  5.  
    if (index != Method::nonvirtual_vtable_index) {
  6.  
    // target_klass might be an arrayKlassOop but all vtables start at
  7.  
    // the same place. The cast is to avoid virtual call and assertion.
  8.  
    InstanceKlass* inst = (InstanceKlass*)target_klass();
  9.  
    method = methodHandle(THREAD, inst->method_at_vtable(index));
  10.  
    }

 

总结

1.method.invoke()方法支持多态特性,其native实现在方法真正执行之前通过动态连接或者虚方法表来实现。

2.框架中使用method.invoke()执行方法调用时,初始获取method对象时,可以先调用一次setAccessable(true),使得后面每次调用invoke()时,节省一次方法修饰符的判断,略微提升性能。业务允许的情况下,Field同样可以如此操作。

3.委托模式可以解决一种方案的多种实现之间自由切换,而代理模式只能根据传入的被代理对象来实现功能。

 

posted on 2020-11-06 20:09  小西红柿  阅读(699)  评论(0)    收藏  举报

导航