• Java反射实现原理分析


    一、反射的用法

    1、如何获取Class反射类

      (1)通过getClass方法:

      Proxy proxy = new ProxyImpl();
      Class proxyClazz = proxy.getClass();

      (2)通过Class.forName方法 

      Proxy proxy = new ProxyImpl();
      Class proxyClazz = Class.forName("com.dh.yjt.SpringBootDemo.test.Reflect.Proxy");

      (3)通过.class 

      Proxy proxy = new ProxyImpl();
      Class proxyClazz = Proxy.class;

    2、获取类型信息

      反射的一大好处就是可以允许我们在运行期间获取对象的类型信息,例如需要再运行期间获取对象方法信息,并执行该方法,可以通过以下方式:

      首先创建一个接口及其实现类,其中实现类的中方法可见性为不同级别:

      class ProxyImpl implements Proxy{
            public void run(){
                System.out.println("run");
            }
    
            public void publicFun(){
                System.out.println("publicFun");
            }
    
            private void privateFun(){
                System.out.println("privateFun");
            }
    
            void packageFun(){
                System.out.println("packageFun");
            }
    
            protected void protectedFun(){
                System.out.println("protectedFun");
            }
        }
    
        interface Proxy{
            public void run();
        }

      然后可以通过反射获取对象中的方法并执行:

       @Test
        public void fun() throws Exception {
            Proxy proxy = new ProxyImpl();
            proxy.run();
            callHiddenMethod(proxy,"publicFun");
            callHiddenMethod(proxy,"privateFun");
            callHiddenMethod(proxy,"packageFun");
            callHiddenMethod(proxy,"protectedFun");
        }
    
        void callHiddenMethod(Object a, String methodName) throws Exception {
            Method g = a.getClass().getDeclaredMethod(methodName);//根据名称获取声明的方法
            g.setAccessible(true);//设置可见性
            g.invoke(a);//执行方法,入参为该对象
        }

      输出结果: 

      run
      publicFun
      privateFun
      packageFun
      protectedFun

      可以看出,通过反射可以执行对象的所有可见性的方法

    二、反射实现原理

    1、获取Method对象  

      从上面的案例可以看出,调用Class类的getDeclaredMethod可以获取指定方法名和参数的方法对象Method:

      @CallerSensitive
        public Method getDeclaredMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException {
            checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
            Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
            if (method == null) {
                throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
            }
            return method;
        }

       其中privateGetDeclaredMethods方法从缓存或JVM中获取该Class中声明的方法列表,searchMethods方法将从返回的方法列表里找到一个匹配名称和参数的方法对象。 

      private Method[] privateGetDeclaredMethods(boolean publicOnly) {
            checkInitted();
            Method[] res;
            ReflectionData<T> rd = reflectionData();//获取reflectionData,其中缓存了该类的方法、变量等信息
            if (rd != null) {//如果不为空,则返回reflectionData中保存的方法列表
                res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
                if (res != null) return res;
            }
            // No cached value available; request value from VM
         //如果缓存中不存在,则从JVM中获取
            res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
            if (rd != null) {
                if (publicOnly) {
                    rd.declaredPublicMethods = res;
                } else {
                    rd.declaredMethods = res;
                }
            }
            return res;
        }

      其中reflectionData()方法实现如下:

    private ReflectionData<T> reflectionData() {
            SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;//获取当前Class对象的reflectionData
            int classRedefinedCount = this.classRedefinedCount;
            ReflectionData<T> rd;
         //如果reflectionData不为空则返回
            if (useCaches && reflectionData != null &&
                (rd = reflectionData.get()) != null &&
                rd.redefinedCount == classRedefinedCount) {
                return rd;
            }
            // else no SoftReference or cleared SoftReference or stale ReflectionData
            // -> create and replace new instance
         //否则创建新的reflectionData
            return newReflectionData(reflectionData, classRedefinedCount);
        }

       从reflectionData()方法实现可以看出:reflectionData对象是SoftReference类型的,说明在内存紧张时可能会被回收,不过也可以通过-XX:SoftRefLRUPolicyMSPerMB参数控制回收的时机,只要发生GC就会将其回收,如果reflectionData被回收之后,又执行了反射方法,那只能通过newReflectionData方法重新创建一个这样的对象了,

      private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData, int classRedefinedCount) {
            if (!useCaches) return null;//不使用缓存,则返回空
    
            while (true) {
                ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount);
                // try to CAS it...
           //通过CAS操作
                if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) {
                    return rd;
                }
                // else retry
                oldReflectionData = this.reflectionData;
                classRedefinedCount = this.classRedefinedCount;
                if (oldReflectionData != null &&
                    (rd = oldReflectionData.get()) != null &&
                    rd.redefinedCount == classRedefinedCount) {
                    return rd;
                }
            }
        }

      其中ReflectionData定义如下:

      private static class ReflectionData<T> {
            volatile Field[] declaredFields;
            volatile Field[] publicFields;
            volatile Method[] declaredMethods;
            volatile Method[] publicMethods;
            volatile Constructor<T>[] declaredConstructors;
            volatile Constructor<T>[] publicConstructors;
            // Intermediate results for getFields and getMethods
            volatile Field[] declaredPublicFields;
            volatile Method[] declaredPublicMethods;
            volatile Class<?>[] interfaces;
    
            // Value of classRedefinedCount when we created this ReflectionData instance
            final int redefinedCount;
    
            ReflectionData(int redefinedCount) {
                this.redefinedCount = redefinedCount;
            }
        }

       总结:在privateGetDeclaredMethods方法中,如果通过reflectionData()获得的ReflectionData对象不为空,则尝试从ReflectionData对象中获取declaredMethods属性,如果是第一次,或则被GC回收之后,重新初始化后的类属性为空,则需要重新到JVM中获取一次,并赋值给ReflectionData,下次调用就可以使用缓存数据了。

      然后通过searchMethods方法将从返回的方法列表里找到一个匹配名称和参数的方法对象:
      private static Method searchMethods(Method[] methods, String name, Class<?>[] parameterTypes) {
            Method res = null;
            String internedName = name.intern();
            for (int i = 0; i < methods.length; i++) {
                Method m = methods[i];
                if (m.getName() == internedName
                    && arrayContentsEq(parameterTypes, m.getParameterTypes())
                    && (res == null
                        || res.getReturnType().isAssignableFrom(m.getReturnType())))
                    res = m;
            }
    
            return (res == null ? res : getReflectionFactory().copyMethod(res));
        }

       如果找到一个匹配的Method,则重新copy一份返回,即Method.copy()方法:

      Method copy() {
            if (this.root != null)
                throw new IllegalArgumentException("Can not copy a non-root Method");
    
            Method res = new Method(clazz, name, parameterTypes, returnType,
                                    exceptionTypes, modifiers, slot, signature,
                                    annotations, parameterAnnotations, annotationDefault);
            res.root = this;
            // Might as well eagerly propagate this if already present
            res.methodAccessor = methodAccessor;
            return res;
        }

       防止坑1:从代码中可以看出,每次调用getDeclaredMethod方法返回的Method对象其实都是一个新的对象,且新对象的root属性都指向复制前的Method对象,如果需要频繁调用,最好把Method对象缓存起来。

    2、执行method

      获取到指定的方法对象Method之后,就可以调用它的invoke方法了,invoke实现如下:

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

      这里的MethodAccessor对象是invoke方法实现的关键,一开始methodAccessor为空,需要调用acquireMethodAccessor生成一个新的MethodAccessor对象,MethodAccessor本身就是一个接口,实现如下:

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

      在acquireMethodAccessor方法中,主要通过ReflectionFactory类的newMethodAccessor创建一个实现了MethodAccessor接口的对象,实现如下:

      public MethodAccessor newMethodAccessor(Method var1) {
            checkInitted();
            if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {
                return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());
            } else {
                NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1);
                DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);
                var2.setParent(var3);
                return var3;
            }
        } 

      在ReflectionFactory类中,有2个重要的字段:noInflation(默认false)和inflationThreshold(默认15),在checkInitted方法中可以通过-Dsun.reflect.inflationThreshold=xxx-Dsun.reflect.noInflation=true对这两个字段重新设置,而且只会设置一次;

      如果noInflationfalse,方法newMethodAccessor都会返回DelegatingMethodAccessorImpl对象,DelegatingMethodAccessorImpl的类实现: 

    class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
        private MethodAccessorImpl delegate;
    
        DelegatingMethodAccessorImpl(MethodAccessorImpl var1) {
            this.setDelegate(var1);
        }
    
        public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
            return this.delegate.invoke(var1, var2);
        }
    
        void setDelegate(MethodAccessorImpl var1) {
            this.delegate = var1;
        }
    }
      其实,DelegatingMethodAccessorImpl对象就是一个代理对象,负责调用被代理对象delegateinvoke方法,其中delegate参数目前是NativeMethodAccessorImpl对象,所以最终Methodinvoke方法调用的是NativeMethodAccessorImpl对象invoke方法,实现如下:
      public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
            if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
                MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(),
                                                                   this.method.getName(),
                                                                   this.method.getParameterTypes(),
                                                                   this.method.getReturnType(),
                                                                   this.method.getExceptionTypes(),
                                                                   this.method.getModifiers()); this.parent.setDelegate(var3); } return invoke0(this.method, var1, var2); }

       这里用到了ReflectionFactory类中的inflationThreshold,当delegate调用了15次invoke方法之后,如果继续调用就通过MethodAccessorGenerator类的generateMethod方法生成MethodAccessorImpl对象,并设置为delegate对象,这样下次执行Method.invoke时,就调用新建的MethodAccessor对象的invoke()方法了。

      防止踩坑2:如果多次执行Method的invoke方法,每超过15次就会创建一个新的MethodAccessorImpl对象,因此会导致内存增涨

    参考

      1、Java反射机制应用实践  http://www.importnew.com/24042.html

      2、深入分析Java方法反射的实现原理  https://www.jianshu.com/p/3ea4a6b57f87

      3、假笨说-从一起GC血案谈到反射原理  https://mp.weixin.qq.com/s/5H6UHcP6kvR2X5hTj_SBjA?

  • 相关阅读:
    Unreal Engine 4 Based Materials
    PhysX Clothing for UE4
    UE4中使用URL图片
    开始创作自己的VR作品——VR故事叙述终极指南
    UE4里的自定义深度功能
    Mybatis27题
    java 备用待迁移
    几个算法题目
    数据结构算法题目
    Mybatis 面试题
  • 原文地址:https://www.cnblogs.com/aiqiqi/p/10691116.html
Copyright © 2020-2023  润新知