深入理解Java中的反射机制和使用原理!详细解析invoke方法的执行和使用 (5)

Reflection.ensureMemberAccess方法继续检查权限.若检查通过就更新缓存,这样下一次同一个类调用同一个方法时就不用执行权限检查了,这是一种简单的缓存机制
由于JMMhappens-before规则能够保证缓存初始化能够在写缓存之间发生,因此两个cache不需要声明为volatile

检查权限的工作到此结束.如果没有通过检查就会抛出异常,如果通过检查就会到下一步

调用MethodAccessor的invoke方法

Method.invoke() 不是自身实现反射调用逻辑,而是通过sun.refelect.MethodAccessor来处理

Method对象的基本构成:

每个Java方法有且只有一个Method对象作为root, 相当于根对象,对用户不可见

当创建Method对象时,代码中获得的Method对象相当于其副本或者引用

root对象持有一个MethodAccessor对象,所有获取到的Method对象都共享这一个MethodAccessor对象

必须保证MethodAccessor在内存中的可见性

root对象及其声明:

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;

MethodAccessor:

/** * 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; }

MethodAccessor是一个接口,定义了invoke() 方法,通过Usage可以看出MethodAccessor的具体实现类:

sun.reflect.DelegatingMethodAccessorImpl

sun.reflect.MethodAccessorImpl

sun.reflect.NativeMethodAccessorImpl

第一次调用Java方法对应的Method对象的invoke()方法之前,实现调用逻辑的MethodAccess对象还没有创建

第一次调用时,才开始创建MethodAccessor并更新为root, 然后调用MethodAccessor.invoke() 完成反射调用

/** * NOTE that there is no synchronization used here. * It is correct(though not efficient) to generate more than one MethodAccessor for a given Method. * However, avoiding synchronization will probably make the implementation more scalable. */ 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 { tmp = reflectionFactory.newMethodAccessor(this); setMethodAccessor(tmp); } return tmp; }

methodAccessor实例由reflectionFactory对象操控生成 ,reflectionFactory是在AccessibleObject中声明的:

/** * 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());

sun.reflect.ReflectionFactory方法:

public class ReflectionFactory { private static boolean initted = false; private static Permission reflectionFactoryAccessPerm = new RuntimePermission("reflectionFactoryAccess"); private static ReflectionFactory soleInstance = new ReflectionFactory(); // Provides access to package-private mechanisms in java.lang.reflect private static volatile LangReflectAccess langReflectAccess; /** * "Inflation" mechanism. Loading bytecodes to implement Method.invoke() and Constructor. * newInstance() currently costs 3-4x more than an invocation via native code for the first invocation (though subsequent invocations have been benchmarked to be over 20x faster) * Unfortunately this cost increases startup time for certain applications that use reflection intensively (but only once per class) to bootstrap themselves * To avoid this penalty we reuse the existing JVM entry points for the first few invocations of Methods and Constructors and then switch to the bytecode-based implementations */ // Package-private to be accessible to NativeMethodAccessorImpl and NativeConstructorAccessorImpl private static noInflation = false; private static int inflationThreshold = 15; // 生成MethodAccessor public MethodAccessor newMethodAccessor(Method method) { checkInitted(); 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; } } /** * We have to defer full initialization of this class until after the static initializer is run since java.lang.reflect * Method's static initializer (more properly, that for java.lang.reflect.AccessibleObject) causes this class's to be run, before the system properties are set up */ private static void checkInitted() { if (initted) return; AccessController.doPrivileged( new PrivilegedAction<Void>() { public Void run() { /** * Tests to ensure the system properties table is fully initialized * This is needed because reflection code is called very early in the initialization process (before command-line arguments have been parsed and therefore these user-settable properties installed * We assume that if System.out is non-null then the System class has been fully initialized and that the bulk of the startup code has been 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 new RuntimeException("Unable to parse property sun.reflect.inflationThreshold", e); } } initted = true; return null; } }); } }

实际的MethodAccessor实现有两个版本,一个是Java版本,一个是native版本,两者各有特点:

初次启动时Method.invoke()Constructor.newInstance() 方法采用native方法要比Java方法快3-4倍

启动后native方法又要消耗额外的性能而慢于Java方法

Java实现的版本在初始化时需要较多时间,但长久来说性能较好

这是HotSpot的优化方式带来的性能特性:

跨越native边界会对优化有阻碍作用

为了尽可能地减少性能损耗,HotSpot JDK采用inflation方式:

Java方法在被反射调用时,开头若干次使用native版

等反射调用次数超过阈值时则生成一个专用的MethodAccessor实现类,生成其中的invoke() 方法的字节码

以后对该Java方法的反射调用就会使用Java版本

ReflectionFactory.newMethodAccessor() 生成MethodAccessor对象的逻辑:

native版开始会会生成NativeMethodAccessorImplDelegatingMethodAccessorImpl两个对象

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zydsyj.html