invoke 订阅
《INVOKE》 [1]  为《机动战士高达seed》片头曲(1-13集),由日本滋贺县野洲市出身的歌手、演员、声优西川贵教(t.m.revolution即西川贵教)演唱。 展开全文
《INVOKE》 [1]  为《机动战士高达seed》片头曲(1-13集),由日本滋贺县野洲市出身的歌手、演员、声优西川贵教(t.m.revolution即西川贵教)演唱。
信息
编    曲
浅倉大介
歌曲时长
4:18
歌曲原唱
T.M.Revolution
发行时间
2002-10-30
谱    曲
浅倉大介
音乐风格
摇滚
外文名称
INVOKE
所属专辑
INVOKE
歌曲语言
日语
填    词
井上秋緒
invoke单曲信息
【INVOKE——机动战士高达seed OP1】 【所属专辑】《机动战士高达 IV》【作词】井上秋绪【作曲】浅仓大介【歌】T.M. Revolution
收起全文
精华内容
下载资源
问答
  • Ivoke-WCMDump 什么是Credential Manager ...从Credential Manager导出Windows凭据的Powershell脚本 https://github.com/peewpw/Invoke-WCMDump PS>Import-Module .\Invoke-WCMDump.ps1 ...Invoke-WCMDump
  • Invoke-ARPScan.ps1

    2021-04-04 22:16:05
    Invoke-ARPScan.ps1
  • 主要介绍了详解Java中Method的Invoke方法,需要的朋友可以参考下
  • 主要介绍了Java反射机制及Method.invoke详解,本文讲解了JAVA反射机制、得到某个对象的属性、得到某个类的静态属性、执行某对象的方法、执行某个类的静态方法等内容,需要的朋友可以参考下
  • 主要介绍了c# Invoke和BeginInvoke 区别分析,需要的朋友可以参考下
  • 主要给大家介绍了关于在PowerShell中使用curl(Invoke-WebRequest)的方法教程,文中通过详细的示例代码给大家介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
  • npm install vue - router - invoke - webpack - plugin - D cnpm cnpm install vue - router - invoke - webpack - plugin - D 纱 yarn add vue - router - invoke - webpack - plugin - D 什么是自动生成路线 ...
  • Invoke-Mimikatz.txt

    2019-03-01 13:32:26
    Invoke-Mimikatz
  • invoke_impl.rar

    2020-04-24 16:12:02
    std::invoke函数模板的两种实现源码,通过实现invoke,对C++模板编程,SFINAE机制,编译期分支,类型转发,类成员指针都有非常好的理解。第一种实现方式需要C++17,VS2019编译运行通过,第二种方式VS2017上编译运行...
  • Invoke-WCMDump-master1.rar

    2021-06-10 12:59:43
    使用 Invoke-WCMDump 加powershell 获取windows凭证密码 使用文档地址:https://blog.csdn.net/caperxi/article/details/117775522
  • 主要介绍了Java Method类及invoke方法原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 主要介绍了C#中Invoke 和 BeginInvoke 的真正涵义,需要的朋友可以参考下
  • NULL 博文链接:https://xgia7.iteye.com/blog/691889
  • Invoke-WCMDump.rar

    2021-03-03 21:55:36
    获取RDP记录脚本
  • tag_invoke 我的C ++ 20实现tag_invoke,在WG21论文P1895R0中进行了描述。
  • C# Invoke调用Demo

    2014-05-22 00:21:33
    C# Invoke多线程调用Demo......
  • NULL 博文链接:https://liumayulingyan.iteye.com/blog/1900122
  • 委托delegate invoke的简单源代码,适合委托初学者!
  • 《精通.NET互操作P/Invoke,C++Interop和COM Interop》介绍Windows平台上的托管代码与非托管代码之间进行互操作的各种技术,包括由.NET提供的各种互操作方法、属性以及各种工具的用法及其工作原理。《精通.NET互操作...
  • Invoke反射

    2014-07-30 11:23:41
    本程序实现Invoke反射,内置说明txt文档,可以参考
  • Invoke-Phant0m:Windows事件日志杀手
  • java反射之Method的invoke方法实现

    万次阅读 多人点赞 2018-07-29 00:31:48
    在框架中经常会会用到method.invoke()方法,用来执行某个的对象的目标方法。以前写代码用到反射时,总是获取先获取Method,然后传入对应的Class实例对象执行方法。然而前段时间研究invoke方法时,发现invoke方法居然...

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

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

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

    public class MethodInvoke {
    
    	public static void main(String[] args) throws Exception {
    		Method animalMethod = Animal.class.getDeclaredMethod("print");
    		Method catMethod = Cat.class.getDeclaredMethod("print");
    		
    		Animal animal = new Animal();
    		Cat cat = new Cat();
    		animalMethod.invoke(cat);
    		animalMethod.invoke(animal);
    		
    		catMethod.invoke(cat);
    		catMethod.invoke(animal);
    	}
    	
    }
    
    class Animal {
    	
    	public void print() {
    		System.out.println("Animal.print()");
    	}
    	
    }
    
    class Cat extends Animal {
    	
    	@Override
    	public void print() {
    		System.out.println("Cat.print()");
    	}
    	
    }

    代码中,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的方法,因此这一次会抛出异常。代码打印结果为:

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

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

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

    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。

        public void setAccessible(boolean flag) throws SecurityException {
            SecurityManager sm = System.getSecurityManager();
            if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
            setAccessible0(this, flag);
        }
    
        private static void setAccessible0(AccessibleObject obj, boolean flag)
            throws SecurityException
        {
            if (obj instanceof Constructor && flag == true) {
                Constructor<?> c = (Constructor<?>)obj;
                if (c.getDeclaringClass() == Class.class) {
                    throw new SecurityException("Can not make a java.lang.Class" +
                                                " constructor accessible");
                }
            }
            obj.override = flag;
        }

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

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

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

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

        private volatile MethodAccessor methodAccessor;
        private Method root;
        
        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);
                setMethodAccessor(tmp);
            }
    
            return tmp;
        }
    
        void setMethodAccessor(MethodAccessor accessor) {
            methodAccessor = accessor;
            // Propagate up
            if (root != null) {
                root.setMethodAccessor(accessor);
            }
        }
    
        Method copy() {
            Method res = new Method(clazz, name, parameterTypes, returnType,
                                    exceptionTypes, modifiers, slot, signature,
                                    annotations, parameterAnnotations, annotationDefault);
            res.root = this;
            res.methodAccessor = methodAccessor;
            return res;
        }

    综合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)方法来创建的。

        public MethodAccessor newMethodAccessor(Method method) {
            checkInitted();
    
            if (noInflation) {
                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);
                acc.setParent(res);
                return res;
            }
        }

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

        private static void checkInitted() {
            if (initted) return;
            AccessController.doPrivileged(
                new PrivilegedAction<Void>() {
                    public Void run() {
    
                        if (System.out == null) {
                            // java.lang.System not yet fully initialized
                            return null;
                        }
    
                        String val = System.getProperty("sun.reflect.noInflation");
                        if (val != null && val.equals("true")) {
                            noInflation = true;
                        }
    
                        val = System.getProperty("sun.reflect.inflationThreshold");
                        if (val != null) {
                            try {
                                inflationThreshold = Integer.parseInt(val);
                            } catch (NumberFormatException e) {
                                throw (RuntimeException)
                                    new RuntimeException("Unable to parse property sun.reflect.inflationThreshold").
                                        initCause(e);
                            }
                        }
    
                        initted = true;
                        return null;
                    }
                });
        }

    可以通过启动参数-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()方法实现。

        public Object invoke(Object obj, Object[] args) 
            throws IllegalArgumentException, InvocationTargetException
        {
            if (++numInvocations > ReflectionFactory.inflationThreshold()) {
                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);
        }
    
        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对象。那么当多次调用后,必然会生成两个重复功能的代理类。当然,一般情况下,生成两个代理类并没有较大的影响。

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

    public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
    
    	public GeneratedMethodAccessor1 () {
    	    super();
    	}
    	
    	public Object invoke(Object obj, Object[] args)
    	        throws IllegalArgumentException, InvocationTargetException 
    	{
    		if (!(obj instanceof Cat)) {
    			throw new ClassCastException();
    		}
    		if (args != null && args.length != 0) {
    			throw new IllegalArgumentException();
    		}
    		
    		try {
    			Cat cat = (Cat) obj;
    			cat.print();
    			return null;
    		} catch (Throwable e) {
    			throw new InvocationTargetException(e, "invoke error");
    		}
    	}
    	
    }

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

    openJDK下载地址

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

    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_InvokeMethod(), 一般以JVM_开头的函数定义在jvm.cpp文件中,不熟悉的话可以通过头文件jvm.h看出来。继续追踪,发现jvm.cpp文件位于spot\src\share\vm\prims文件夹下。

    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)) {
            // Only for primitive type vm allocates memory for java object.
            // See box() method.
            JvmtiExport::post_vm_object_alloc(JavaThread::current(), result);
          }
        }
        return res;
      } else {
        THROW_0(vmSymbols::java_lang_StackOverflowError());
      }
    JVM_END

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

    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* m = klass->method_with_idnum(slot);
      if (m == NULL) {
        THROW_MSG_0(vmSymbols::java_lang_InternalError(), "invoke");
      }
      methodHandle method(THREAD, m);
    
      return invoke(klass, method, receiver, override, ptypes, rtype, args, true, THREAD);
    }
    
    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 {
          // resolve based on the receiver
          if (reflected_method->method_holder()->is_interface()) {
            // resolve interface call
            if (ReflectionWrapResolutionErrors) {
              // new default: 6531596
              // Match resolution errors with those thrown due to reflection inlining
              // Linktime resolution & IllegalAccessCheck already done by Class.getMethod()
              method = resolve_interface_call(klass, reflected_method, target_klass, receiver, THREAD);
              if (HAS_PENDING_EXCEPTION) {
              // Method resolution threw an exception; wrap it in an InvocationTargetException
                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 {
            // if the method can be overridden, we resolve using the vtable index.
            assert(!reflected_method->has_itable_index(), "");
            int index = reflected_method->vtable_index();
            method = reflected_method;
            if (index != Method::nonvirtual_vtable_index) {
              // target_klass might be an arrayKlassOop but all vtables start at
              // the same place. The cast is to avoid virtual call and assertion.
              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()));
                }
              }
            }
          }
        }
      }
    
      // I believe this is a ShouldNotGetHere case which requires
      // an internal vtable bug. If you ever get this please let Karen know.
      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()));
      }
    
      // In the JDK 1.4 reflection implementation, the security check is
      // done at the Java level
      if (!(JDK_Version::is_gte_jdk14x_version() && UseNewReflection)) {
    
      // Access checking (unless overridden by Method)
      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);
      }
    
      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");
    
      // All oops (including receiver) is passed in as Handles. An potential oop is returned as an
      // oop (i.e., NOT as an handle)
      JavaValue result(rtype);
      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);
      }
    }

    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));
    methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, methodHandle method,
                                                    KlassHandle recv_klass, Handle receiver, TRAPS) {
      assert(!method.is_null() , "method should not be null");
    
      CallInfo info;
      Symbol*  signature  = method->signature();
      Symbol*  name       = method->name();
      LinkResolver::resolve_interface_call(info, receiver, recv_klass, klass,
                                           name, signature,
                                           KlassHandle(), false, true,
                                           CHECK_(methodHandle()));
      return info.selected_method();
    }

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

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

     

    总结

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

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

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

     

     

    参考文章:

    JAVA深入研究——Method的Invoke方法

    展开全文
  • Dubbo invoke命令使用

    千次阅读 2020-10-15 11:50:53
    首先使用telnet命令进入控制台命令:telnet ip 端口 例如你的如果dubbo.protocol.port=29952 ... invoke XxxService.xxxMethod({“prop”: “value”}, 1, “1”) 如果注入的参数是对象(com.yunji.bigdata.po...

    首先使用telnet命令进入控制台
    命令:telnet ip 端口

    例如你的如果dubbo.protocol.port=29952

    那么就是 telnet localhost 2995

    然后使用invoke命令注入:
      如果注入的是json
      那就直接传入json串就ok了,如果是基础数据类型,也可以分别对应参数直接传
      invoke XxxService.xxxMethod({“prop”: “value”}, 1, “1”)
      如果注入的参数是对象(com.yunji.bigdata.portrait.bo.PageSearchVO。具体的方法名: selectCustomerDataFromMysql(PageSearchVO var1)

    对象PageSearchVO:

    public class PageSearchVO implements Serializable {
        private String version = "1.0";
        private Integer size = 100000;
        private Integer pageNum;
        private Integer groupId;
    
        //getter  setter方法
    
    }


    我们也是按照json的格式传,只不过在每个对象后都需要指定具体的这个对象具体所属的类型。
    invoke XxxService.selectCustomerDataFromMysql({"version":"1.0","size":100, "pageNum":1, "groupId":1000088,"class":"com.yunji.bigdata.portrait.bo.PageSearchVO"})

     

    dubbo官网invoke文档:

    invoke

    1. invoke XxxService.xxxMethod(1234, "abcd", {"prop" : "value"}): 调用服务的方法
    2. invoke com.xxx.XxxService.XxxService.xxxMethod(1234, "abcd", {"prop" : "value"}): 调用全路径服务的方法
    3. invoke xxxMethod(1234, "abcd", {"prop" : "value"}): 调用服务的方法(自动查找包含此方法的服务)
    4. invoke xxxMethod({"name":"zhangsan","age":12,"class":"org.apache.dubbo.qos.legacy.service.Person"}) :当有参数重载,或者类型转换失败的时候,可以通过增加class属性指定需要转换类
    5. 当参数为Map<Integer,T>,key的类型为Integer时,建议指定类型。例如invoke com.xxx.xxxApiService({"3":0.123, "class":"java.util.HashMap"})
    展开全文
  • dubbo中invoke多种调用入参方式

    千次阅读 2020-03-28 09:26:15
    dubbo提供了通过invoke方式调用接口,接下来我们通过由浅入深讲解如何通过invoke传递参数调用接口. 说明 1.在虚拟机(192.168.233.129)上部署了zk 2.本地(127.0.0.1)部署项目,接口注册到zk上 准备 1.需要安装zookeeper...

    在日常的Java开发工作中,我们经常需要调用Dubbo接口.
    Dubbo提供了通过invoke调用的方式,接下来由浅入深讲解不同的入参该如何传递.

    首先使用telnet方式连接,连接成功之后,才可以使用invoke调用方法.

    ls命令可以检验是否存在提供者以及方法.

    在这里插入图片描述

    场景一

    // 入参是一个简单的字符串
    public String query(String address);
    
    // 调用
    invoke QueryUserInfoFacade.query("浙江省杭州市余杭区")
    

    场景二

    // 入参是一个字符串和整型
    public String query(String address, Integer year);
    
    // 调用
    invoke QueryUserInfoFacade.query("浙江省杭州市余杭区", 2020)
    

    场景三

    public String query(UserInfoCondition condition);
    public class UserInfoCondition {
        private String address;
        private String year;
    }
    
    // 调用
    invoke QueryUserInfoFacade.query({"address":"浙江省杭州市余杭区","year":2020})
    
    {
        "address":"浙江省杭州市余杭区",
        "year":2020
    }
    

    如果入参是一个对象,那么就使用一个花括号{}表示这个对象,对象里面的属性和属性值使用键值对key-value表示,key表示对象的属性,value表示属性的值

    场景四

    public String query(UserInfoCondition condition);
    public class UserInfoCondition {
    	// 对象的属性是一个List
        private List<String> addressList;
    }
    
    // 调用
    invoke QueryUserInfoFacade.query({"addressList":["浙江省杭州市余杭区","四川省成都市"]})
    

    既然接收的是一个对象condition,那么首先使用{}表示,属性使用键值对key-value表示. 对象里面有个List属性,相当于是数组,使用中括号[]表示,最后表示就是{“addressList”:[“浙江省杭州市余杭区”,“四川省成都市”]}.

    {
        "addressList":[
            "浙江省杭州市余杭区",
            "四川省成都市"
        ]
    }
    

    场景五

    public String query(UserInfoCondition condition);
    public class UserInfoCondition {
        private List<UserInfo> userList;
    }
    public class UserInfo {
        private String address;
        private Integer year;
    }
    
    // 调用
    invoke QueryUserInfoFacade.query({"userList":[{"address":"江苏","year":2019},{"address":"北京","year":2020}]})
    

    根据前面的总结,我们知道列表使用数组表示,即中括号[ ].只是这次列表中不是简单的类型,而是一个对象,对象使用中括号表示.

    {
        "userList":[
            {
                "address":"江苏",
                "year":2019
            },
            {
                "address":"北京",
                "year":2020
            }
        ]
    }
    

    场景六

    public String query(UserInfoCondition condition);
    public class UserInfoCondition {
    	// List中是一个Map
        private List<Map<String, Integer>> mList;
    }
    
    // 调用
    invoke QueryUserInfoFacade.query({"mList":[{"李白":29},{"王维":30}]})
    

    在这里插入图片描述

    {
        "mList":[
            {
                "李白":29
            },
            {
                "王维":30
            }
        ]
    }
    
    

    1.列表依然是使用数组表示.
    2.将Map<String, Integer>看作是一个对象.

    场景七

    public String query(UserInfoCondition condition);
    public class UserInfoCondition {
    	// Map的键是一个字符串类型,值是一个对象类型
        private List<Map<String, UserInfo>> mUserList;
    }
    public class UserInfo {
        private String address;
        private Integer year;
    }
    
    // 调用
    invoke QueryUserInfoFacade.query({"mUserList":[{"作者一":{"address":"四川","year":2010}},{"作者二":{"address":"陕西","year":2030}}]})
    
    
    {
        "mUserList":[
            {
                "作者一":{
                    "address":"四川",
                    "year":2010
                }
            },
            {
                "作者二":{
                    "address":"陕西",
                    "year":2030
                }
            }
        ]
    }
    

    场景八

    public String query(UserInfoCondition condition);
    public class UserInfoCondition {
    	// Map的key不再是字符串类型,而是Integer类型
        private List<Map<Integer, UserInfo>> mUserList;
    }
    

    如果按照上面场景七分析的方式传参会报错.我给Dubbo官方提了这个bug,官方也给了回复以及修复.

    实际的传参应该是

    // 调用
    invoke QueryUserInfoFacade.query({"mUserList":[{1:{"address":"HANGZHOU","year":"2020"},"class":"java.util.HashMap"},{2:{"address":"ZHEJIANG","year":"2021"},"class":"java.util.HashMap"}]})
    或
    invoke QueryUserInfoFacade.query({"mUserList":[{"1":{"address":"HANGZHOU","year":"2020"},"class":"java.util.HashMap"},{"2":{"address":"ZHEJIANG","year":"2021"},"class":"java.util.HashMap"}]})
    
    {
        "mUserList":[
            {
                "1":{
                    "address":"HANGZHOU",
                    "year":"2020"
                },
                "class":"java.util.HashMap"
            },
            {
                "2":{
                    "address":"ZHEJIANG",
                    "year":"2021"
                },
                "class":"java.util.HashMap"
            }
        ]
    }
    
    

    场景九

    String query(Set<Integer> years);
    
    // 调用
    invoke QueryUserInfoFacade.query([1,2,3])
    
    String query(Integer year, Set<String> months);
    
    // 调用
    invoke QueryUserInfoFacade.query(2020,["1","3","5"])
    
    public String query(UserInfo userInfo);
    public class UserInfo {
        private Set<Integer> years
    }
    
    // 调用
    invoke QueryUserInfoFacade.query({"years":[2010,2015,2020]})
    

    和List类似,将Set也看作是数组即可.

    场景十 内部类场景

    public String query(UserInfo userInfo);
    
    package com.xyz.service;
    public class UserCondition {
    	public class UserInfo {
        	private String address;
        	private Integer year;
    	}
    }
    
    
    // 调用
    invoke QueryUserInfoFacade.query({"class":"com.xyz.service.UserCondition$UserInfo","address":"浙江","year": 2020})
    

    内部类使用$符号

    {
        "class":"com.xyz.service.UserCondition$UserInfo",
        "address":"浙江",
        "year":2020
    }
    

    场景十一 入参是枚举

    public String query(Color color);
    public enum Color {
        BLUE(2),
        RED(5);
        private Integer value;
        Color(Integer value) {
            this.value = value;
        }
    }
    
    
    // 调用
    invoke QueryUserInfoFacade.query({"class":"com.infuq.condition.Color","name":"RED"})
    
    {
        "class":"com.infuq.condition.Color",
        "name":"RED"
    }
    
    String query(UserInfo userInfo);
    public class UserInfo {
        private String year;
        private String address;
        private Color color;
    }
    
    // 调用
    invoke QueryUserInfoFacade.query({"class":"com.infuq.condition.UserInfo","color":{"name":"BLUE"}})
    
    {
        "class":"com.infuq.condition.UserInfo",
        "color":{
            "name":"BLUE"
        }
    }
    

    全文总结

    1.对象使用{ }表示
    2.List/Set使用[ ]表示
    3.Map使用{ }表示
    4.内部类使用$符号
    5.枚举类使用name
    6.在使用{ }的时候最好指定"class".

    在平时工作中,我会使用python的方式调用invoke,代码如下

    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    
    import socket
    import telnetlib
    import sys
    
    
    class DubboTelnet(object):
    
        def __init__(self, host, port):
            self.host = host
            self.port = port
            self.__connect_timeout = 10
            self.__read_timeout = 10
            self.__encoding = 'UTF-8'
            self.__finish = 'dubbo>'
    
        def invoke(self, command):
            try:
                telnet = telnetlib.Telnet(host=self.host, port=self.port, timeout=self.__connect_timeout)
            except socket.error as err:
                print("[host:%s port:%s] %s" % (self.host, self.port, err))
                return
    
            # 触发Dubbo提示符
            telnet.write(b'\n')
            # 执行命令
            telnet.read_until(self.__finish.encode(), timeout=self.__read_timeout)
            telnet.write(command.encode() + b"\n")
            # 获取结果
            data = ''
            while str(data).find(self.__finish) == -1:
                data = telnet.read_very_eager()
            data = data.decode().split("\n")[0]
            telnet.close()
            return data
    
    
    def main(host='127.0.0.1', port=20880):
    
        conn = DubboTelnet(host, port)
        
        cmd = 'invoke QueryUserInfoFacade.query({"class":"com.infuq.condition.UserInfo","color":{"name":"BLUE"}})'
        
        ret = conn.invoke(cmd)
        print(ret)
    
    if __name__ == "__main__":
        try:
            main('127.0.0.1', 20880)
        finally:
            sys.exit()
    
    
    

    个人站点
    语雀

    公众号

    在这里插入图片描述

    展开全文
  • invoke.hpp:小时-源码

    2021-05-28 20:05:04
    invoke.hpp std :: invoke / std :: apply for C ++ 11/14 要求 > = 4.9 > = 3.8 > = 2015年 安装 是仅标头的库。 您需要做的就是将headers文件从headers目录复制到您的项目中,并包括它们: # include " ...
  • Java反射之Method的invoke方法实现

    千次阅读 2020-11-11 21:55:35
    在框架中经常会会用到method.invoke()方法,用来执行某个的对象的目标方法。以前写代码用到反射时,总是获取先获取Method,然后传入对应的Class实例对象执行方法。然而前段时间研究invoke方法时,发现invoke方法居然...

    使用reflect(反射)包下面的Field和Method类获得类的属性和方法,并对属性和方法进行操作。

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

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

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

    public class MethodInvoke {
    	public static void main(String[] args) throws Exception {
    		Method animalMethod = Animal.class.getDeclaredMethod("print");
    		Method catMethod = Cat.class.getDeclaredMethod("print");
    	
    		Animal animal = new Animal();
    		Cat cat = new Cat();
    		animalMethod.invoke(cat);
    		animalMethod.invoke(animal);
    		
    		catMethod.invoke(cat);
    		catMethod.invoke(animal);
    	}
    }
     
    class Animal {
    	public void print() {
    		System.out.println("Animal.print()");
    	}
    }
     
    class Cat extends Animal {
    	@Override
    	public void print() {
    		System.out.println("Cat.print()");
    	}
    }

    代码中,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的方法,因此这一次会抛出异常。代码打印结果为:

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

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

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

    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。

    public void setAccessible(boolean flag) throws SecurityException {
            SecurityManager sm = System.getSecurityManager();
            if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
            setAccessible0(this, flag);
        }
     
        private static void setAccessible0(AccessibleObject obj, boolean flag)
            throws SecurityException
        {
            if (obj instanceof Constructor && flag == true) {
                Constructor<?> c = (Constructor<?>)obj;
                if (c.getDeclaringClass() == Class.class) {
                    throw new SecurityException("Can not make a java.lang.Class" +
                                            " constructor accessible");
            }
        }
        obj.override = flag;
    }

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

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

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

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

        private volatile MethodAccessor methodAccessor;
        private Method root;
        
        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);
                setMethodAccessor(tmp);
            }
     
            return tmp;
        }
     
        void setMethodAccessor(MethodAccessor accessor) {
            methodAccessor = accessor;
            // Propagate up
            if (root != null) {
                root.setMethodAccessor(accessor);
            }
        }
     
        Method copy() {
            Method res = new Method(clazz, name, parameterTypes, returnType,
                                    exceptionTypes, modifiers, slot, signature,
                                    annotations, parameterAnnotations, annotationDefault);
            res.root = this;
            res.methodAccessor = methodAccessor;
            return res;
        }

    综合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的实现机制。

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

    public MethodAccessor newMethodAccessor(Method method) {
            checkInitted();
     
        if (noInflation) {
            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);
            acc.setParent(res);
            return res;
        }
    }

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

     

    浪费时间

    直接上链接:https://blog.csdn.net/wenyuan65/article/details/81145900

     

    展开全文
  • C# invoke 和 begininvoke 用法

    千次阅读 2019-01-24 18:41:16
    invoke和begininvoke 区别 一直对invoke和begininvoke的使用和概念比较混乱,这两天看了些资料,对这两个的用法和原理有了些新的认识和理解。  首先说下,invoke和begininvoke的使用有两种情况:  1. control中...
  • Invoke-AltDSBackdoor-源码

    2021-05-04 12:35:10
    示例:PS C:\ Users \ test \ Desktop> Invoke-ADSBackdoor -URL “ Invoke-Shellcode -Lhost 192.168.1.138 -LPort 2222 -Payload windows / meterpreter / reverse_https -Force“这将使用Invoke-Shellcode.ps1...
  • } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //获取方法名 String methodName = method.getName(); //获取方法参数类型们 Class[] parameterTypes = method...
  • Invoke()的使用

    千次阅读 2021-03-16 13:41:23
    Invoke()的作用是:在应用程序的主线程上执行指定的委托。一般应用:在辅助线程中修改UI线程( 主线程 )中对象的属性时,调用this.Invoke(); 1. //测试的窗体 2. public class TestForm : Form 3. { 4. //...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 485,642
精华内容 194,256
关键字:

invoke