java反射-通过invoke方法深入探索反射机制
虽说有一定原因是在考科三,但是第三篇没有及时完成还是有一定原因是因为五一都出去浪了,这一篇算是额外的。
我一直在犹豫invoke方法要不要单开一篇写,因为虽说invoke(调用)方法会在某些报错的时候在报错的位置中可以看到这个函数,可以看出这个方法应用比较广泛,但是我实际接触的其实也还少,一时间对于它的应用也找不到例子,只能拎出源码看看。
1、invoke()
invoke()方法定义在java.lang.reflect.Method中,源码如下,前面长长的一串注释详细地描述了invoke方法的使用以及可能抛出的错误。
-
invoke方法应该由Method对象调用,并传入调用该method的实例对象obj以及需要传入的参数args。
-
当使用invoke调用static方法的时候,obj参数应当为null
-
当使用invoke调用的方法无参数的时候,args参数的长度应当为0或者为null
-
当使用invoke调用实例方法,则使用《 Java语言规范,第二版》第15.12.4.4节中记录的动态方法查找来调用它;
-
当使用invoke调用类的static方法时类还未被加载,则会触发类加载。
-
根据invoke调用的方法返回返回值,返回值都是Object,这个Object可能指向某个类的实例,也可能是是空(void),也可能返回数组对象,数组对象需要使用类Array进行操作。
/** * Invokes the underlying method represented by this {@code Method} * object, on the specified object with the specified parameters. * Individual parameters are automatically unwrapped to match * primitive formal parameters, and both primitive and reference * parameters are subject to method invocation conversions as * necessary. * * <p>If the underlying method is static, then the specified {@code obj} * argument is ignored. It may be null. * * <p>If the number of formal parameters required by the underlying method is * 0, the supplied {@code args} array may be of length 0 or null. * * <p>If the underlying method is an instance method, it is invoked * using dynamic method lookup as documented in The Java Language * Specification, Second Edition, section 15.12.4.4; in particular, * overriding based on the runtime type of the target object will occur. * * <p>If the underlying method is static, the class that declared * the method is initialized if it has not already been initialized. * * <p>If the method completes normally, the value it returns is * returned to the caller of invoke; if the value has a primitive * type, it is first appropriately wrapped in an object. However, * if the value has the type of an array of a primitive type, the * elements of the array are <i>not</i> wrapped in objects; in * other words, an array of primitive type is returned. If the * underlying method return type is void, the invocation returns * null. * * @param obj the object the underlying method is invoked from * @param args the arguments used for the method call * @return the result of dispatching the method represented by * this object on {@code obj} with parameters * {@code args} * * @exception IllegalAccessException if this {@code Method} object * is enforcing Java language access control and the underlying * method is inaccessible. * @exception IllegalArgumentException if the method is an * instance method and the specified object argument * is not an instance of the class or interface * declaring the underlying method (or of a subclass * or implementor thereof); if the number of actual * and formal parameters differ; if an unwrapping * conversion for primitive arguments fails; or if, * after possible unwrapping, a parameter value * cannot be converted to the corresponding formal * parameter type by a method invocation conversion. * @exception InvocationTargetException if the underlying method * throws an exception. * @exception NullPointerException if the specified object is null * and the method is an instance method. * @exception ExceptionInInitializerError if the initialization * provoked by this method fails. */ @CallerSensitive 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; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args); } try { Class c = String.class; char[] chr = {'0','1','2','3'}; Object str = c.getConstructor(char[].class).newInstance(chr); Method method = c.getMethod("charAt", int.class); System.out.println(method.invoke(str,2)); //返回数组 method = c.getMethod("toCharArray"); Object chr2 = method.invoke(str); System.out.println(Array.get(chr2,2)); //调用static对象 method = c.getMethod("valueOf",char[].class); Object str2 = method.invoke(null,chr); System.out.println(str2); } catch (Exception e) { e.printStackTrace(); }
2、invoke()源码分析
@CallerSensitive 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; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args); }
如果从头到尾进行分析……
2.1 @CallerSensitive
注解
Improve the security of the JDK's method-handle implementation by replacing the existing hand-maintained list of caller-sensitive methods with a mechanism that accurately identifies such methods and allows their callers to be discovered reliably.
通过使用准确识别此类方法并允许可靠地发现其调用方的机制来替换JDK的方法句柄实现的安全性,以替换现有的手动维护的调用方敏感方法列表。
当一个调用敏感者(caller-sensitive)需要确定它的直接调用者的类,它会通过调用native方法sun.reflect.Reflection.getCallerClass()
来实现。Reflection类位于调用栈中的0帧位置,sun.reflect.Reflection.getCallerClass()
方法返回调用栈中从0帧开始的第x帧中的类实例。
这个注解@CallerSensitive
是为了堵住漏洞用的。曾经有黑客通过构造双重反射 来提升权限,原理是当时反射只检查固定深度的调用者的类,看它有没有特权,例如固定看两层的调用者(getCallerClass(2)
)。如果我的类本来没足够权限群访问某些信息,那我就可以通过双重反射去达到目的:反射相关的类是有很高权限的,而在 我->反射1->反射2 这样的调用链上,反射2检查权限时看到的是反射1的类,这就被欺骗了,导致安全漏洞。使用CallerSensitive
后,getCallerClass
不再用固定深度去寻找actual caller(“我”),而是把所有跟反射相关的接口方法都标注上CallerSensitive
,搜索时凡看到该注解都直接跳过,这样就有效解决了前面举例的问题
2.2 invoke可能抛出的异常
-
IllegalAccessException
: 当使用invoke()调用权限不足(譬如private修饰)的方法,并且没有使用setAccessible(true)
会抛出这个异常。 -
IllegalArgumentException
:传入invoke方法的实例对象不是指定类、接口或其子类的实例,或者传入的参数长度与调用的方法所需的不符合,抛出这个异常。 -
InvocationTargetException
:当使用invoke调用的方法中报错,抛出这个异常。 -
NullPointerException
:当需要传入实例对象的时候传入了null -
ExceptionInInitializerError:
如果类的初始化报错
2.3 invoke权限检查
if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, obj, modifiers); } }
a) override
--是否忽略权限检查
首先,变量override
定义在AccessibleObject
类中,AccessibleObject
类是 Field
、Method
和 Constructor
对象的基类。override
变量提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力,它值默认是false,表示需要权限调用规则,调用方法时需要检查权限;我们也可以用setAccessible
方法设置为true,若override
的值为true,表示忽略权限规则,调用方法时无需检查权限(也就是说可以调用任意的private方法,违反了封装)。
如果override属性为默认值false,则进行进一步的权限检查:
b)检查方法是否为public
用Reflection.quickCheckMemberAccess(clazz, modifiers)
方法检查方法是否为public,如果是的话跳出本步;如果不是public方法,那么用Reflection.getCallerClass()
方法获取调用这个方法的Class对象,调用checkAccess
再进行一次快速的权限检验。
可以看到sun.reflect.Reflection.quickCheckMemberAccess()
通过native方法getClassAccessFlags
检索写入类文件的访问标志与传入的modifiers标志取与之后进行Modifier.isPublic()
的判断,这个方法总的来说就是检查需要调用的方法是否为public。
//sun.reflect.Reflection /** A quick "fast-path" check to try to avoid getCallerClass() calls. */ public static boolean quickCheckMemberAccess(Class<?> memberClass, int modifiers) { return Modifier.isPublic(getClassAccessFlags(memberClass) & modifiers); } //sun.reflect.Reflection /** Retrieves the access flags written to the class file. For inner classes these flags may differ from those returned by Class.getModifiers(), which searches the InnerClasses attribute to find the source-level access flags. This is used instead of Class.getModifiers() for run-time access checks due to compatibility reasons; see 4471811. Only the values of the low 13 bits (i.e., a mask of 0x1FFF) are guaranteed to be valid. */ public static native int getClassAccessFlags(Class<?> c); //java.lang.reflect.Modifier /** * Return {@code true} if the integer argument includes the * {@code public} modifier, {@code false} otherwise. * * @param mod a set of modifiers * @return {@code true} if {@code mod} includes the * {@code public} modifier; {@code false} otherwise. */ public static boolean isPublic(int mod) { return (mod & PUBLIC) != 0; } /* * Access modifier flag constants from tables 4.1, 4.4, 4.5, and 4.7 of * <cite>The Java™ Virtual Machine Specification</cite> */ /** * The {@code int} value representing the {@code public} * modifier. */ public static final int PUBLIC = 0x00000001;
c)checkAccess
--进行更加深入的权限检查
checkAccess
方法定义在AccessibleObject
类中。
// Shared access checking logic. // For non-public members or members in package-private classes, // it is necessary to perform somewhat expensive security checks. // If the security check succeeds for a given class, it will // always succeed (it is not affected by the granting or revoking // of permissions); we speed up the check in the common case by // remembering the last Class for which the check succeeded. // // The simple security check for Constructor is to see if // the caller has already been seen, verified, and cached. // (See also Class.newInstance(), which uses a similar method.) // // A more complicated security check cache is needed for Method and Field // The cache can be either null (empty cache), a 2-array of {caller,target}, // or a caller (with target implicitly equal to this.clazz). // In the 2-array case, the target is always different from the clazz. volatile Object securityCheckCache; void checkAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers) throws IllegalAccessException { if (caller == clazz) { // quick check return; // ACCESS IS OK } Object cache = securityCheckCache; // read volatile Class<?> targetClass = clazz; if (obj != null && Modifier.isProtected(modifiers) && ((targetClass = obj.getClass()) != clazz)) { // Must match a 2-list of { caller, targetClass }. if (cache instanceof Class[]) { Class<?>[] cache2 = (Class<?>[]) cache; if (cache2[1] == targetClass && cache2[0] == caller) { return; // ACCESS IS OK } // (Test cache[1] first since range check for [1] // subsumes range check for [0].) } } else if (cache == caller) { // Non-protected case (or obj.class == this.clazz). return; // ACCESS IS OK } // If no return, fall through to the slow path. slowCheckMemberAccess(caller, clazz, obj, modifiers, targetClass); }
首先先执行一次快速校验,一旦调用方法的Class正确则权限检查通过。 若未通过,则读取volatile变量securityCheckCache
,检查是否已经通过过slowCheckMemberAccess
检查。 如果上面的所有权限检查都未通过,那么将执行更详细的检查,其实现为:
// Keep all this slow stuff out of line: void slowCheckMemberAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers, Class<?> targetClass) throws IllegalAccessException { Reflection.ensureMemberAccess(caller, clazz, obj, modifiers); // Success: Update the cache. Object cache = ((targetClass == clazz) ? caller : new Class<?>[] { caller, targetClass }); // Note: The two cache elements are not volatile, // but they are effectively final. The Java memory model // guarantees that the initializing stores for the cache // elements will occur before the volatile write. securityCheckCache = cache; // write volatile }
2.4 调用MethodAccessor
的invoke方法
若未通过权限检查则抛出异常,若通过了权限检查,则进行方法调用。
MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args);
可以看到Method.invoke()
实际上并不是自己实现的反射调用逻辑,而是委托给sun.reflect.MethodAccessor
来处理。
//`java.lang.reflect.Method` private volatile MethodAccessor methodAccessor; // For sharing of MethodAccessors. This branching structure is // currently only two levels deep (i.e., one root Method and // potentially many Method objects pointing to it.) // // If this branching structure would ever contain cycles, deadlocks can // occur in annotation code. private Method root;
Method对象的每个Java方法有且只有一个Method对象作为root,它相当于根对象,对用户不可见。当我们创建Method对象时,我们代码中获得的Method对象都相当于它的副本(或引用)。root对象持有一个MethodAccessor
对象,所以所有获取到的Method对象都共享这一个MethodAccessor
对象,因此必须保证它在内存中的可见性。如同上述代码所示,第一次读取methodAccessor
时,methodAccessor
为空,通过acquireMethodAccessor
方法进行创建,之后每一次访问都是通过访问已经创建好的methodAccessor
调用methodAccessor.invoke(obj,args)
。
那么sun.reflect.MethodAccessor.invoke()
方法又实现了什么呢?MethodAccessor
是一个接口,只定义了一个虚方法invoke
。
/** This interface provides the declaration for java.lang.reflect.Method.invoke(). Each Method object is configured with a (possibly dynamically-generated) class which implements this interface. */ public interface MethodAccessor { /** Matches specification in {@link java.lang.reflect.Method} */ public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException; }
那么其实现应该具体看到底是创建了哪一个实现了该接口的类的实例,它具体实现的类包括:
-
sun.reflect.DelegatingMethodAccessorImpl
-
sun.reflect.MethodAccessorImpl
-
sun.reflect.NativeMethodAccessorImpl
a)整个源码过程
//0、java.lang.reflect.Method.acquireMethodAccessor() /*MethodAccessor对象在一个指定method中唯一的,所以即使这个方法中未定义同步,但是要尽量保证同步问题*/ 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); //1、reflectionFactory定义在父类AccessibleObject中,是一个ReflectionFactory类的实例 //2、newMethodAccessor()在进行了一些初始化后进行判断,后创建了不同的子类的实例 setMethodAccessor(tmp); //3、设置MethodAccessor } return tmp; } //1.1、变量reflectionFactory定义在父类java.lang.reflect.AccessibleObject中 /*ReflectionFactory对象用于构建字段、方法、构造器的访问器 *最后返回的是一个static修饰的ReflectionFactory的实例 */ static final ReflectionFactory reflectionFactory = AccessController.doPrivileged( new sun.reflect.ReflectionFactory.GetReflectionFactoryAction()); //1.1.1 sun.reflect.ReflectionFactory.GetReflectionFactoryAction类 /*用户获取实例化反射对象的类 *相比于直接使用getReflectionFactory()的原始调用,这个类可以避免受到调用者权限的限制 *可作为AccessController.doPrivileged()的参数 *最后返回的是一个static修饰的ReflectionFactory的实例 */ public static final class GetReflectionFactoryAction implements PrivilegedAction<ReflectionFactory> { public ReflectionFactory run() { return getReflectionFactory(); } } //1.1.1.1 sun.reflect.ReflectionFactory.getReflectionFactory()方法 /** * Provides the caller with the capability to instantiate reflective * objects. * * <p> First, if there is a security manager, its * <code>checkPermission</code> method is called with a {@link * java.lang.RuntimePermission} with target * <code>"reflectionFactoryAccess"</code>. This may result in a * security exception. * * <p> The returned <code>ReflectionFactory</code> object should be * carefully guarded by the caller, since it can be used to read and * write private data and invoke private methods, as well as to load * unverified bytecodes. It must never be passed to untrusted code. * * @exception SecurityException if a security manager exists and its * <code>checkPermission</code> method doesn't allow * access to the RuntimePermission "reflectionFactoryAccess". */ public static ReflectionFactory getReflectionFactory() { SecurityManager security = System.getSecurityManager(); if (security != null) { // TO DO: security.checkReflectionFactoryAccess(); security.checkPermission(reflectionFactoryAccessPerm); } return soleInstance; } //1.1.1.1.1 最后返回的是一个static修饰的ReflectionFactory的实例 private static final ReflectionFactory soleInstance = new ReflectionFactory(); //1.1.1.1.2 java.security.PrivilegedAction public interface PrivilegedAction<T> { /** * Performs the computation. This method will be called by * {@code AccessController.doPrivileged} after enabling privileges. * * @return a class-dependent value that may represent the results of the * computation. Each class that implements * {@code PrivilegedAction} * should document what (if anything) this value represents. * @see AccessController#doPrivileged(PrivilegedAction) * @see AccessController#doPrivileged(PrivilegedAction, * AccessControlContext) */ T run(); } //2.1 sun.reflect.ReflectionFactory.newMethodAccessor() /* *进行必须的初始化工作,后进行判断: *a) 当类是虚拟机匿名类时: *b) 其他情况时: */ public MethodAccessor newMethodAccessor(Method method) { checkInitted();//确保系统属性表已完全初始化。 //ReflectUtil类是访问权限检查工具,检查类是否为虚拟机匿名类(这与Java语言中的匿名内部类不同) if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) { 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; } } //2.1.1 sun.reflect.ReflectionFactory.checkInitted() /** 在运行静态初始值设定项完成之前,需要推迟对该类的完全初始化。因为java.lang.reflect.Method(准确来说是java.lang.reflect.AccessibleObject)的静态初始值设定项会导致系统属性设置好之前运行此类 */ private static void checkInitted() { if (initted) return;//如果已经初始化过,返回 AccessController.doPrivileged( new PrivilegedAction<Void>() { public Void run() { //测试以确保系统属性表已完全初始化。 // 因为反射代码在初始化过程中很早就被调用(在解析命令行参数之前,因此已安装了这些用户可设置的属性。) // 我们假设如果System.out为非null,则System类已经 完全初始化,并且大部分启动代码已运行。 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 new RuntimeException("Unable to parse property sun.reflect.inflationThreshold", e); } } initted = true; return null; } }); } //2.1.2 sun.reflect.misc.ReflectUtil.isVMAnonymousClass() /** * Checks if {@code Class cls} is a VM-anonymous class as defined by {@link jdk.internal.misc.Unsafe#defineAnonymousClass} * (not to be confused with a Java Language anonymous inner class). */ // 检查cls是否为虚拟机匿名类(这与Java语言中的匿名内部类不同) public static boolean isVMAnonymousClass(Class<?> cls) { // 类名中包含'/' return cls.getName().indexOf('/')>-1; } //3.1 sun.reflect.ReflectionFactory.setMethodAccessor() /** Sets the MethodAccessor object for a java.lang.reflect.Method */ public void setMethodAccessor(Method m, MethodAccessor accessor) { langReflectAccess().setMethodAccessor(m, accessor); //不明白的是langReflectAccess()返回了ReflectionFactory类中的static ReflectionFactory实例soleInstance //然后又调用ReflectionFactory.setMethodAccessor(),似乎进入了循环? } //3.1.1 sun.reflect.ReflectionFactory.langReflectAccess // Provides access to package-private mechanisms in java.lang.reflect private static volatile LangReflectAccess langReflectAccess; //3.1.2 sun.reflect.ReflectionFactory.langReflectAccess() private static LangReflectAccess langReflectAccess() { if (langReflectAccess == null) { // 调用Modifier的静态方法以触发Modifier的初始化,然后运行Modifier类中的静态方法区设置langReflectAccess Modifier.isPublic(Modifier.PUBLIC); } return langReflectAccess; } //3.1.2.1 java.lang.reflect.Modifier静态方法区 /* * Bootstrapping protocol between java.lang and java.lang.reflect * packages */ static { sun.reflect.ReflectionFactory factory = AccessController.doPrivileged( new ReflectionFactory.GetReflectionFactoryAction());//返回了ReflectionFactory类中的static ReflectionFactory实例soleInstance factory.setLangReflectAccess(new java.lang.reflect.ReflectAccess()); } //3.1.2.1.1 java.lang.reflect.ReflectionFactory.setLangReflectAccess() /** Called only by java.lang.reflect.Modifier's static initializer */ public void setLangReflectAccess(LangReflectAccess access) { langReflectAccess = access; } //3.1.3 sun.reflect.LangReflectAccess,接口 public void setMethodAccessor(Method m, MethodAccessor accessor);
b)acquireMethodAccessor()
和newMethodAccessor()
//0、java.lang.reflect.Method.acquireMethodAccessor() /*MethodAccessor对象在一个指定method中唯一的,所以即使这个方法中未定义同步,但是要尽量保证同步问题*/ 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); //1、reflectionFactory定义在父类AccessibleObject中,是一个ReflectionFactory类的实例 //2、newMethodAccessor()在进行了一些初始化后进行判断,后创建了不同的子类的实例 setMethodAccessor(tmp); //3、设置MethodAccessor } return tmp; } //2.1 sun.reflect.ReflectionFactory.newMethodAccessor() /* *进行必须的初始化工作,后进行判断: *a) 当类是虚拟机匿名类时: *b) 其他情况时: */ public MethodAccessor newMethodAccessor(Method method) { checkInitted();//确保系统属性表已完全初始化。 //ReflectUtil类是访问权限检查工具,检查类是否为虚拟机匿名类(这与Java语言中的匿名内部类不同) if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) { 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; } }
根据代码可知,acquireMethodAccessor()
返回的methodAccessor
有两种可能:
一种是MethodAccessorGenerator().generateMethod()
返回的methodAccessor
实例
一种是DelegatingMethodAccessorImpl
和NativeMethodAccessorImpl
的实例
c)MethodAccessorGenerator().generateMethod()
事实上这个我并没有找到最终的结果,因为一个generate()
方法我找不到来源。它既不定义在MethodAccessorGenerator
中,也没有定义在它的父类AccessorGenerator
中,也不在导入的某个类之中……或许是我粗心没有注意到,但是既然没有找到只能到此为止了。这是一个针对虚拟机匿名类的methodAccessor
获取方法,后续有机会再继续了解吧。
//sun.reflect.MethodAccessorGenerator.generateMethod() /** This routine is not thread-safe */ public MethodAccessor generateMethod(Class<?> declaringClass, String name, Class<?>[] parameterTypes, Class<?> returnType, Class<?>[] checkedExceptions, int modifiers) { return (MethodAccessor) generate(declaringClass, name, parameterTypes, returnType, checkedExceptions, modifiers, false, false, null); }
d)DelegatingMethodAccessorImpl
和NativeMethodAccessorImpl
MethodAccessor
是一个接口,它具体实现的类包含sun.reflect.MethodAccessorImpl
, sun.reflect.DelegatingMethodAccessorImpl
和sun.reflect.NativeMethodAccessorImpl
。
其中MethodAccessorImpl
是一个实现了MethodAccessor
的虚类,并未实现invoke()
方法。
DelegatingMethodAccessorImpl
和NativeMethodAccessorImpl
都是MethodAccessorImpl
的子类,但是DelegatingMethodAccessorImpl
构造方法接收一个MethodAccessorImpl
实例并维护这个MethodAccessorImpl
实例,在invoke()
方法中依赖传入的MethodAccessorImpl
实例进行调用,仅仅是做了一层封装,并未涉及invoke()
的具体实现。invoke()
的具体实现在NativeMethodAccessorImpl
之中。
//sun.reflect.MethodAccessor /* * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.reflect; import java.lang.reflect.InvocationTargetException; /** This interface provides the declaration for java.lang.reflect.Method.invoke(). Each Method object is configured with a (possibly dynamically-generated) class which implements this interface. */ public interface MethodAccessor { /** Matches specification in {@link java.lang.reflect.Method} */ public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException; } //sun.reflect.MethodAccessorImpl /* * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.reflect; import java.lang.reflect.InvocationTargetException; /** <P> Package-private implementation of the MethodAccessor interface which has access to all classes and all fields, regardless of language restrictions. See MagicAccessor. </P> <P> This class is known to the VM; do not change its name without also changing the VM's code. </P> <P> NOTE: ALL methods of subclasses are skipped during security walks up the stack. The assumption is that the only such methods that will persistently show up on the stack are the implementing methods for java.lang.reflect.Method.invoke(). </P> */ abstract class MethodAccessorImpl extends MagicAccessorImpl implements MethodAccessor { /** Matches specification in {@link java.lang.reflect.Method} */ public abstract Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException; }
//sun.reflect.DelegatingMethodAccessorImpl /* * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.reflect; import java.lang.reflect.InvocationTargetException; /** Delegates its invocation to another MethodAccessorImpl and can change its delegate at run time. */ class DelegatingMethodAccessorImpl extends MethodAccessorImpl { private MethodAccessorImpl delegate; DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) { setDelegate(delegate); } public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException { return delegate.invoke(obj, args); } void setDelegate(MethodAccessorImpl delegate) { this.delegate = delegate; } }
//sun.reflect.NativeMethodAccessorImpl /* * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.reflect; import java.lang.reflect.*; import sun.reflect.misc.ReflectUtil; /** Used only for the first few invocations of a Method; afterward, switches to bytecode-based implementation */ class NativeMethodAccessorImpl extends MethodAccessorImpl { private final Method method; private DelegatingMethodAccessorImpl parent; private int numInvocations; NativeMethodAccessorImpl(Method method) { this.method = method; } public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException { // 是否匿名类中的方法?如果是,则将封装类的实例parent中的维护的MethodAccessorImpl替换 if (++numInvocations > ReflectionFactory.inflationThreshold() && !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); } //调用native方法invoke0() return invoke0(method, obj, args); } void setParent(DelegatingMethodAccessorImpl parent) { this.parent = parent; } private static native Object invoke0(Method m, Object obj, Object[] args); }
在NativeMethodAccessorImpl
之中维护了一个封装类DelegatingMethodAccessorImpl
类的实例parent
,以及一个常量Method
类的实例,以及一个int类型的数值numInvocations
。
然后在invoke()
方法中继续判断method是否匿名类中的方法,如果是,替换调用的MethodAccessor
的实例类型,之后返回native方法invoke0(method, obj, args)
。
那么这次就到此为止吧。
3、总结
大部分都在找源码,有时候不知道如何组织描述的语言,不过牵着一条线走下去然后慢慢还原整个过程的这个过程还算有趣吧,也比预料之中深入了更多,花的时间也比想象地多了许多。java反射相关的类除了java.lang.Class
,大多包含在java.lang.reflect.*
之下,但是也涉及了许多sun.reflect.*
之下的类。不过这次有关invoke()
方法的深入探究,更多涉及的是Method相关的类、权限访问类或者某些类中Method相关方法,下面仅仅做部分类的整理。
3.1 java.lang.reflect.AccessibleObject
类
AccessibleObject
类是Field
,Method
和Constructor
类对象的基类。 它提供了将反射对象标记为在使用它时抑制默认Java语言访问控制检查的功能。 当使用Fields
,Methods
或Constructors
类对象来设置或获取字段,调用方法,或创建和初始化新的类实例时,执行访问分别检查(对于public,默认(包)访问,protected和private成员) 。 在反射对象中设置可访问标志允许具有足够权限的复杂应用程序(如Java对象序列化或其他持久性机制)以被禁止的方式操作对象。
//java.lang.reflect.AccessibleObject /* * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.lang.reflect; import java.security.AccessController; import sun.reflect.Reflection; import sun.reflect.ReflectionFactory; import java.lang.annotation.Annotation; /** * The AccessibleObject class is the base class for Field, Method and * Constructor objects. It provides the ability to flag a reflected * object as suppressing default Java language access control checks * when it is used. The access checks--for public, default (package) * access, protected, and private members--are performed when Fields, * Methods or Constructors are used to set or get fields, to invoke * methods, or to create and initialize new instances of classes, * respectively. * * <p>Setting the {@code accessible} flag in a reflected object * permits sophisticated applications with sufficient privilege, such * as Java Object Serialization or other persistence mechanisms, to * manipulate objects in a manner that would normally be prohibited. * * <p>By default, a reflected object is <em>not</em> accessible. * * @see Field * @see Method * @see Constructor * @see ReflectPermission * * @since 1.2 */ public class AccessibleObject implements AnnotatedElement { /** * The Permission object that is used to check whether a client * has sufficient privilege to defeat Java language access * control checks. */ static final private java.security.Permission ACCESS_PERMISSION = new ReflectPermission("suppressAccessChecks"); /** * Convenience method to set the {@code accessible} flag for an * array of objects with a single security check (for efficiency). * * <p>First, if there is a security manager, its * {@code checkPermission} method is called with a * {@code ReflectPermission("suppressAccessChecks")} permission. * * <p>A {@code SecurityException} is raised if {@code flag} is * {@code true} but accessibility of any of the elements of the input * {@code array} may not be changed (for example, if the element * object is a {@link Constructor} object for the class {@link * java.lang.Class}). In the event of such a SecurityException, the * accessibility of objects is set to {@code flag} for array elements * upto (and excluding) the element for which the exception occurred; the * accessibility of elements beyond (and including) the element for which * the exception occurred is unchanged. * * @param array the array of AccessibleObjects * @param flag the new value for the {@code accessible} flag * in each object * @throws SecurityException if the request is denied. * @see SecurityManager#checkPermission * @see java.lang.RuntimePermission */ public static void setAccessible(AccessibleObject[] array, boolean flag) throws SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(ACCESS_PERMISSION); for (int i = 0; i < array.length; i++) { setAccessible0(array[i], flag); } } /** * Set the {@code accessible} flag for this object to * the indicated boolean value. A value of {@code true} indicates that * the reflected object should suppress Java language access * checking when it is used. A value of {@code false} indicates * that the reflected object should enforce Java language access checks. * * <p>First, if there is a security manager, its * {@code checkPermission} method is called with a * {@code ReflectPermission("suppressAccessChecks")} permission. * * <p>A {@code SecurityException} is raised if {@code flag} is * {@code true} but accessibility of this object may not be changed * (for example, if this element object is a {@link Constructor} object for * the class {@link java.lang.Class}). * * <p>A {@code SecurityException} is raised if this object is a {@link * java.lang.reflect.Constructor} object for the class * {@code java.lang.Class}, and {@code flag} is true. * * @param flag the new value for the {@code accessible} flag * @throws SecurityException if the request is denied. * @see SecurityManager#checkPermission * @see java.lang.RuntimePermission */ public void setAccessible(boolean flag) throws SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(ACCESS_PERMISSION); setAccessible0(this, flag); } /* Check that you aren't exposing java.lang.Class.<init> or sensitive fields in java.lang.Class. */ 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("Cannot make a java.lang.Class" + " constructor accessible"); } } obj.override = flag; } /** * Get the value of the {@code accessible} flag for this object. * * @return the value of the object's {@code accessible} flag */ public boolean isAccessible() { return override; } /** * Constructor: only used by the Java Virtual Machine. */ protected AccessibleObject() {} // Indicates whether language-level access checks are overridden // by this object. Initializes to "false". This field is used by // Field, Method, and Constructor. // // NOTE: for security purposes, this field must not be visible // outside this package. boolean override; // Reflection factory used by subclasses for creating field, // method, and constructor accessors. Note that this is called // very early in the bootstrapping process. static final ReflectionFactory reflectionFactory = AccessController.doPrivileged( new sun.reflect.ReflectionFactory.GetReflectionFactoryAction()); /** * @throws NullPointerException {@inheritDoc} * @since 1.5 */ public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { throw new AssertionError("All subclasses should override this method"); } /** * {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @since 1.5 */ @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { return AnnotatedElement.super.isAnnotationPresent(annotationClass); } /** * @throws NullPointerException {@inheritDoc} * @since 1.8 */ @Override public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) { throw new AssertionError("All subclasses should override this method"); } /** * @since 1.5 */ public Annotation[] getAnnotations() { return getDeclaredAnnotations(); } /** * @throws NullPointerException {@inheritDoc} * @since 1.8 */ @Override public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) { // Only annotations on classes are inherited, for all other // objects getDeclaredAnnotation is the same as // getAnnotation. return getAnnotation(annotationClass); } /** * @throws NullPointerException {@inheritDoc} * @since 1.8 */ @Override public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) { // Only annotations on classes are inherited, for all other // objects getDeclaredAnnotationsByType is the same as // getAnnotationsByType. return getAnnotationsByType(annotationClass); } /** * @since 1.5 */ public Annotation[] getDeclaredAnnotations() { throw new AssertionError("All subclasses should override this method"); } // Shared access checking logic. // For non-public members or members in package-private classes, // it is necessary to perform somewhat expensive security checks. // If the security check succeeds for a given class, it will // always succeed (it is not affected by the granting or revoking // of permissions); we speed up the check in the common case by // remembering the last Class for which the check succeeded. // // The simple security check for Constructor is to see if // the caller has already been seen, verified, and cached. // (See also Class.newInstance(), which uses a similar method.) // // A more complicated security check cache is needed for Method and Field // The cache can be either null (empty cache), a 2-array of {caller,target}, // or a caller (with target implicitly equal to this.clazz). // In the 2-array case, the target is always different from the clazz. volatile Object securityCheckCache; void checkAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers) throws IllegalAccessException { if (caller == clazz) { // quick check return; // ACCESS IS OK } Object cache = securityCheckCache; // read volatile Class<?> targetClass = clazz; if (obj != null && Modifier.isProtected(modifiers) && ((targetClass = obj.getClass()) != clazz)) { // Must match a 2-list of { caller, targetClass }. if (cache instanceof Class[]) { Class<?>[] cache2 = (Class<?>[]) cache; if (cache2[1] == targetClass && cache2[0] == caller) { return; // ACCESS IS OK } // (Test cache[1] first since range check for [1] // subsumes range check for [0].) } } else if (cache == caller) { // Non-protected case (or obj.class == this.clazz). return; // ACCESS IS OK } // If no return, fall through to the slow path. slowCheckMemberAccess(caller, clazz, obj, modifiers, targetClass); } // Keep all this slow stuff out of line: void slowCheckMemberAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers, Class<?> targetClass) throws IllegalAccessException { Reflection.ensureMemberAccess(caller, clazz, obj, modifiers); // Success: Update the cache. Object cache = ((targetClass == clazz) ? caller : new Class<?>[] { caller, targetClass }); // Note: The two cache elements are not volatile, // but they are effectively final. The Java memory model // guarantees that the initializing stores for the cache // elements will occur before the volatile write. securityCheckCache = cache; // write volatile } }