zoukankan      html  css  js  c++  java
  • 深入理解java反射原理

      反射是java的一个特性,这一特性也使得它给了广大的第三方框架和开发过者很大的想像空间。

      通过反射,java可以动态的加载未知的外部配置对象,临时生成字节码进行加载使用,从而使代码更灵活!可以极大地提高应用的扩展性!

      但是,除了停留在使用其华丽功能,我们还可以去看看其实现!

    主要看两个方法的使用:

    来个例子!

    public class HelloReflect {
        public static void main(String[] args) {
            try {
                // 1. 使用外部配置的实现,进行动态加载类
                TempFunctionTest test = (TempFunctionTest)Class.forName("com.tester.HelloReflect").newInstance();
                test.sayHello("call directly");
                // 2. 根据配置的函数名,进行方法调用(不需要通用的接口抽象)
                Object t2 = new TempFunctionTest();
                Method method = t2.getClass().getDeclaredMethod("sayHello", String.class);
                method.invoke(test, "method invoke");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e ) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        
        public void sayHello(String word) {
            System.out.println("hello," + word);
        }
    
    }

      运行结果显而易见!我们来看执行流程!

    1. 反射获取类实例 Class.forName("C.a.xxx");

      首先调用了 java.lang.Class 的静态方法,获取类信息!

        @CallerSensitive
        public static Class<?> forName(String className)
                    throws ClassNotFoundException {
            // 先通过反射,获取调用进来的类信息,从而获取当前的 classLoader
            Class<?> caller = Reflection.getCallerClass();
            // 调用native方法进行获取class信息
            return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
        }

      forName()反射获取类信息,并没有将实现留给了java,而是交给了jvm去加载!

      主要是先获取 ClassLoader, 然后调用 native 方法,获取信息,加载类则是回调 java.lang.ClassLoader.

      最后,jvm又会回调 ClassLoader 进类加载!

        // 
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            return loadClass(name, false);
        }
        
            // sun.misc.Launcher
            public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
                int var3 = var1.lastIndexOf(46);
                if(var3 != -1) {
                    SecurityManager var4 = System.getSecurityManager();
                    if(var4 != null) {
                        var4.checkPackageAccess(var1.substring(0, var3));
                    }
                }
    
                if(this.ucp.knownToNotExist(var1)) {
                    Class var5 = this.findLoadedClass(var1);
                    if(var5 != null) {
                        if(var2) {
                            this.resolveClass(var5);
                        }
    
                        return var5;
                    } else {
                        throw new ClassNotFoundException(var1);
                    }
                } else {
                    return super.loadClass(var1, var2);
                }
            }
        // java.lang.ClassLoader
        protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
            // 先获取锁
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                // 如果已经加载了的话,就不用再加载了
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
                    try {
                        // 双亲委托加载
                        if (parent != null) {
                            c = parent.loadClass(name, false);
                        } else {
                            c = findBootstrapClassOrNull(name);
                        }
                    } catch (ClassNotFoundException e) {
                        // ClassNotFoundException thrown if class not found
                        // from the non-null parent class loader
                    }
    
                    // 父类没有加载到时,再自己加载
                    if (c == null) {
                        // If still not found, then invoke findClass in order
                        // to find the class.
                        long t1 = System.nanoTime();
                        c = findClass(name);
    
                        // this is the defining class loader; record the stats
                        sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        sun.misc.PerfCounter.getFindClasses().increment();
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
        
        protected Object getClassLoadingLock(String className) {
            Object lock = this;
            if (parallelLockMap != null) {
                // 使用 ConcurrentHashMap来保存锁
                Object newLock = new Object();
                lock = parallelLockMap.putIfAbsent(className, newLock);
                if (lock == null) {
                    lock = newLock;
                }
            }
            return lock;
        }
        
        protected final Class<?> findLoadedClass(String name) {
            if (!checkName(name))
                return null;
            return findLoadedClass0(name);
        }

      下面来看一下 newInstance() 的实现方式!

        // 首先肯定是 Class.newInstance
        @CallerSensitive
        public T newInstance()
            throws InstantiationException, IllegalAccessException
        {
            if (System.getSecurityManager() != null) {
                checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
            }
    
            // NOTE: the following code may not be strictly correct under
            // the current Java memory model.
    
            // Constructor lookup
            // newInstance() 其实相当于调用类的无参构造函数,所以,首先要找到其无参构造器
            if (cachedConstructor == null) {
                if (this == Class.class) {
                    // 不允许调用 Class 的 newInstance() 方法
                    throw new IllegalAccessException(
                        "Can not call newInstance() on the Class for java.lang.Class"
                    );
                }
                try {
                    // 获取无参构造器
                    Class<?>[] empty = {};
                    final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
                    // Disable accessibility checks on the constructor
                    // since we have to do the security check here anyway
                    // (the stack depth is wrong for the Constructor's
                    // security check to work)
                    java.security.AccessController.doPrivileged(
                        new java.security.PrivilegedAction<Void>() {
                            public Void run() {
                                    c.setAccessible(true);
                                    return null;
                                }
                            });
                    cachedConstructor = c;
                } catch (NoSuchMethodException e) {
                    throw (InstantiationException)
                        new InstantiationException(getName()).initCause(e);
                }
            }
            Constructor<T> tmpConstructor = cachedConstructor;
            // Security check (same as in java.lang.reflect.Constructor)
            int modifiers = tmpConstructor.getModifiers();
            if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                if (newInstanceCallerCache != caller) {
                    Reflection.ensureMemberAccess(caller, this, null, modifiers);
                    newInstanceCallerCache = caller;
                }
            }
            // Run constructor
            try {
                // 调用无参构造器
                return tmpConstructor.newInstance((Object[])null);
            } catch (InvocationTargetException e) {
                Unsafe.getUnsafe().throwException(e.getTargetException());
                // Not reached
                return null;
            }
        }

     newInstance() 主要做了三件事:

      1. 权限检测,如果不通过直接抛出异常;

      2. 查找无参构造器,并将其缓存起来;

      3. 调用具体方法的无参构造方法,生成实例并返回;

    下面是获取构造器的过程:

        private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
                                            int which) throws NoSuchMethodException
        {
            // 获取所有构造器
            Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
            for (Constructor<T> constructor : constructors) {
                if (arrayContentsEq(parameterTypes,
                                    constructor.getParameterTypes())) {
                    return getReflectionFactory().copyConstructor(constructor);
                }
            }
            throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
        }

    getConstructor0() 为获取匹配的构造方器;分三步:
      1. 先获取所有的constructors, 然后通过进行参数类型比较;
      2. 找到匹配后,通过 ReflectionFactory copy一份constructor返回;
      3. 否则抛出 NoSuchMethodException;

        // 获取当前类所有的构造方法,通过jvm或者缓存
        // Returns an array of "root" constructors. These Constructor
        // objects must NOT be propagated to the outside world, but must
        // instead be copied via ReflectionFactory.copyConstructor.
        private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) {
            checkInitted();
            Constructor<T>[] res;
            // 调用 reflectionData(), 获取保存的信息,使用软引用保存,从而使内存不够可以回收
            ReflectionData<T> rd = reflectionData();
            if (rd != null) {
                res = publicOnly ? rd.publicConstructors : rd.declaredConstructors;
                // 存在缓存,则直接返回
                if (res != null) return res;
            }
            // No cached value available; request value from VM
            if (isInterface()) {
                @SuppressWarnings("unchecked")
                Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0];
                res = temporaryRes;
            } else {
                // 使用native方法从jvm获取构造器
                res = getDeclaredConstructors0(publicOnly);
            }
            if (rd != null) {
                // 最后,将从jvm中读取的内容,存入缓存
                if (publicOnly) {
                    rd.publicConstructors = res;
                } else {
                    rd.declaredConstructors = res;
                }
            }
            return res;
        }
        
        // Lazily create and cache ReflectionData
        private ReflectionData<T> reflectionData() {
            SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;
            int classRedefinedCount = this.classRedefinedCount;
            ReflectionData<T> rd;
            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
            return newReflectionData(reflectionData, classRedefinedCount);
        }
        
        // 新创建缓存,保存反射信息
        private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData,
                                                    int classRedefinedCount) {
            if (!useCaches) return null;
    
            // 使用cas保证更新的线程安全性,所以反射是保证线程安全的
            while (true) {
                ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount);
                // try to CAS it...
                if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) {
                    return rd;
                }
                // 先使用CAS更新,如果更新成功,则立即返回,否则测查当前已被其他线程更新的情况,如果和自己想要更新的状态一致,则也算是成功了
                oldReflectionData = this.reflectionData;
                classRedefinedCount = this.classRedefinedCount;
                if (oldReflectionData != null &&
                    (rd = oldReflectionData.get()) != null &&
                    rd.redefinedCount == classRedefinedCount) {
                    return rd;
                }
            }
        }

    如上,privateGetDeclaredConstructors(), 获取所有的构造器主要步骤;
      1. 先尝试从缓存中获取;
      2. 如果缓存没有,则从jvm中重新获取,并存入缓存,缓存使用软引用进行保存,保证内存可用;

    另外,使用 relactionData() 进行缓存保存;ReflectionData 的数据结构如下!

        // reflection data that might get invalidated when JVM TI RedefineClasses() is called
        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;
            }
        }

      其中,还有一个点,就是如何比较构造是否是要查找构造器,其实就是比较类型完成相等就完了,有一个不相等则返回false。

        private static boolean arrayContentsEq(Object[] a1, Object[] a2) {
            if (a1 == null) {
                return a2 == null || a2.length == 0;
            }
    
            if (a2 == null) {
                return a1.length == 0;
            }
    
            if (a1.length != a2.length) {
                return false;
            }
    
            for (int i = 0; i < a1.length; i++) {
                if (a1[i] != a2[i]) {
                    return false;
                }
            }
    
            return true;
        }
        // sun.reflect.ReflectionFactory
        /** Makes a copy of the passed constructor. The returned
            constructor is a "child" of the passed one; see the comments
            in Constructor.java for details. */
        public <T> Constructor<T> copyConstructor(Constructor<T> arg) {
            return langReflectAccess().copyConstructor(arg);
        }
        
        // java.lang.reflect.Constructor, copy 其实就是新new一个 Constructor 出来
        Constructor<T> copy() {
            // This routine enables sharing of ConstructorAccessor objects
            // among Constructor objects which refer to the same underlying
            // method in the VM. (All of this contortion is only necessary
            // because of the "accessibility" bit in AccessibleObject,
            // which implicitly requires that new java.lang.reflect
            // objects be fabricated for each reflective call on Class
            // objects.)
            if (this.root != null)
                throw new IllegalArgumentException("Can not copy a non-root Constructor");
    
            Constructor<T> res = new Constructor<>(clazz,
                                                   parameterTypes,
                                                   exceptionTypes, modifiers, slot,
                                                   signature,
                                                   annotations,
                                                   parameterAnnotations);
            // root 指向当前 constructor
            res.root = this;
            // Might as well eagerly propagate this if already present
            res.constructorAccessor = constructorAccessor;
            return res;
        }
        

      通过上面,获取到 Constructor 了!

    接下来就只需调用其相应构造器的 newInstance(),即返回实例了!

        // return tmpConstructor.newInstance((Object[])null); 
        // java.lang.reflect.Constructor
        @CallerSensitive
        public T newInstance(Object ... initargs)
            throws InstantiationException, IllegalAccessException,
                   IllegalArgumentException, InvocationTargetException
        {
            if (!override) {
                if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                    Class<?> caller = Reflection.getCallerClass();
                    checkAccess(caller, clazz, null, modifiers);
                }
            }
            if ((clazz.getModifiers() & Modifier.ENUM) != 0)
                throw new IllegalArgumentException("Cannot reflectively create enum objects");
            ConstructorAccessor ca = constructorAccessor;   // read volatile
            if (ca == null) {
                ca = acquireConstructorAccessor();
            }
            @SuppressWarnings("unchecked")
            T inst = (T) ca.newInstance(initargs);
            return inst;
        }
        // sun.reflect.DelegatingConstructorAccessorImpl
        public Object newInstance(Object[] args)
          throws InstantiationException,
                 IllegalArgumentException,
                 InvocationTargetException
        {
            return delegate.newInstance(args);
        }
        // sun.reflect.NativeConstructorAccessorImpl
        public Object newInstance(Object[] args)
            throws InstantiationException,
                   IllegalArgumentException,
                   InvocationTargetException
        {
            // We can't inflate a constructor belonging to a vm-anonymous class
            // because that kind of class can't be referred to by name, hence can't
            // be found from the generated bytecode.
            if (++numInvocations > ReflectionFactory.inflationThreshold()
                    && !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
                ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
                    new MethodAccessorGenerator().
                        generateConstructor(c.getDeclaringClass(),
                                            c.getParameterTypes(),
                                            c.getExceptionTypes(),
                                            c.getModifiers());
                parent.setDelegate(acc);
            }
    
            // 调用native方法,进行调用 constructor
            return newInstance0(c, args);
        }

      返回构造器的实例后,可以根据外部进行进行类型转换,从而使用接口或方法进行调用实例功能了。

    2. 反射获取方法 c.class.getDeclaredMethod();Method.invoke() 反射调用方法!

      第一步,先获取 Method; 

        // java.lang.Class
        @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;
        }

    忽略第一个检查权限,剩下就只有两个动作了!
      1. 获取所有方法列表;
      2. 根据方法名称和方法列表,选出符合要求的方法;
      3. 如果没有找到相应方法,抛出异常,否则返回对应方法;

      所以,先看一下怎样获取类声明的所有方法?

        // Returns an array of "root" methods. These Method objects must NOT
        // be propagated to the outside world, but must instead be copied
        // via ReflectionFactory.copyMethod.
        private Method[] privateGetDeclaredMethods(boolean publicOnly) {
            checkInitted();
            Method[] res;
            ReflectionData<T> rd = reflectionData();
            if (rd != null) {
                res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
                if (res != null) return res;
            }
            // No cached value available; request value from VM
            res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
            if (rd != null) {
                if (publicOnly) {
                    rd.declaredPublicMethods = res;
                } else {
                    rd.declaredMethods = res;
                }
            }
            return res;
        }

      很相似,和获取所有构造器的方法很相似,都是先从缓存中获取方法,如果没有,则从jvm中获取!

      不同的是,方法列表需要进行过滤 Reflection.filterMethods;当然后面看来,这个方法我们一般不会派上用场!

        // sun.misc.Reflection
        public static Method[] filterMethods(Class<?> containingClass, Method[] methods) {
            if (methodFilterMap == null) {
                // Bootstrapping
                return methods;
            }
            return (Method[])filter(methods, methodFilterMap.get(containingClass));
        }
        // 可以过滤指定的方法,一般为空,如果要指定过滤,可以调用 registerMethodsToFilter(), 或者...
        private static Member[] filter(Member[] members, String[] filteredNames) {
            if ((filteredNames == null) || (members.length == 0)) {
                return members;
            }
            int numNewMembers = 0;
            for (Member member : members) {
                boolean shouldSkip = false;
                for (String filteredName : filteredNames) {
                    if (member.getName() == filteredName) {
                        shouldSkip = true;
                        break;
                    }
                }
                if (!shouldSkip) {
                    ++numNewMembers;
                }
            }
            Member[] newMembers =
                (Member[])Array.newInstance(members[0].getClass(), numNewMembers);
            int destIdx = 0;
            for (Member member : members) {
                boolean shouldSkip = false;
                for (String filteredName : filteredNames) {
                    if (member.getName() == filteredName) {
                        shouldSkip = true;
                        break;
                    }
                }
                if (!shouldSkip) {
                    newMembers[destIdx++] = member;
                }
            }
            return newMembers;
        }

      第二步,根据方法名和参数类型过滤指定方法返回:

        private static Method searchMethods(Method[] methods,
                                            String name,
                                            Class<?>[] parameterTypes)
        {
            Method res = null;
            // 使用常量池,避免重复创建String
            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));
        }

    大概意思看得明白,就是匹配到方法名,然后参数类型匹配,才可以!
      但是,可以看到,匹配到一个方法,并没有退出for循环,而是继续进行匹配!
      这里,是匹配最精确的子类进行返回(最优匹配)
      最后,还是通过 ReflectionFactory, copy 方法后返回!

    第三步,调用 method.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);
        }

      invoke时,是通过 MethodAccessor 进行调用的,而 MethodAccessor 是个接口,在第一次时调用 acquireMethodAccessor() 进行新创建!

        // 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,否则调用 ReflectionFactory 创建新的 MethodAccessor
                methodAccessor = tmp;
            } else {
                // Otherwise fabricate one and propagate it up to the root
                tmp = reflectionFactory.newMethodAccessor(this);
                setMethodAccessor(tmp);
            }
    
            return tmp;
        }
        // sun.reflect.ReflectionFactory
        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;
            }
        }

    两个Accessor详情:

    //     NativeMethodAccessorImpl / DelegatingMethodAccessorImpl
    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
        {
            // We can't inflate methods belonging to vm-anonymous classes because
            // that kind of class can't be referred to by name, hence can't be
            // found from the generated bytecode.
            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);
            }
    
            return invoke0(method, obj, args);
        }
    
        void setParent(DelegatingMethodAccessorImpl parent) {
            this.parent = parent;
        }
    
        private static native Object invoke0(Method m, Object obj, Object[] args);
    }
    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;
        }
    }
    View Code

      进行 ma.invoke(obj, args); 调用时,调用 DelegatingMethodAccessorImpl.invoke(); 

      最后被委托到 NativeMethodAccessorImpl.invoke(), 即:

        public Object invoke(Object obj, Object[] args)
            throws IllegalArgumentException, InvocationTargetException
        {
            // We can't inflate methods belonging to vm-anonymous classes because
            // that kind of class can't be referred to by name, hence can't be
            // found from the generated bytecode.
            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);
            }
    
            // invoke0 是个 native 方法,由jvm进行调用业务方法!从而完成反射调用功能!
            return invoke0(method, obj, args);
        }
        

       其中, 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);
        }

    generate() 戳详情!

        /** This routine is not thread-safe */
        private MagicAccessorImpl generate(final Class<?> declaringClass,
                                           String name,
                                           Class<?>[] parameterTypes,
                                           Class<?>   returnType,
                                           Class<?>[] checkedExceptions,
                                           int modifiers,
                                           boolean isConstructor,
                                           boolean forSerialization,
                                           Class<?> serializationTargetClass)
        {
            ByteVector vec = ByteVectorFactory.create();
            asm = new ClassFileAssembler(vec);
            this.declaringClass = declaringClass;
            this.parameterTypes = parameterTypes;
            this.returnType = returnType;
            this.modifiers = modifiers;
            this.isConstructor = isConstructor;
            this.forSerialization = forSerialization;
    
            asm.emitMagicAndVersion();
    
            // Constant pool entries:
            // ( * = Boxing information: optional)
            // (+  = Shared entries provided by AccessorGenerator)
            // (^  = Only present if generating SerializationConstructorAccessor)
            //     [UTF-8] [This class's name]
            //     [CONSTANT_Class_info] for above
            //     [UTF-8] "sun/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}"
            //     [CONSTANT_Class_info] for above
            //     [UTF-8] [Target class's name]
            //     [CONSTANT_Class_info] for above
            // ^   [UTF-8] [Serialization: Class's name in which to invoke constructor]
            // ^   [CONSTANT_Class_info] for above
            //     [UTF-8] target method or constructor name
            //     [UTF-8] target method or constructor signature
            //     [CONSTANT_NameAndType_info] for above
            //     [CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info] for target method
            //     [UTF-8] "invoke" or "newInstance"
            //     [UTF-8] invoke or newInstance descriptor
            //     [UTF-8] descriptor for type of non-primitive parameter 1
            //     [CONSTANT_Class_info] for type of non-primitive parameter 1
            //     ...
            //     [UTF-8] descriptor for type of non-primitive parameter n
            //     [CONSTANT_Class_info] for type of non-primitive parameter n
            // +   [UTF-8] "java/lang/Exception"
            // +   [CONSTANT_Class_info] for above
            // +   [UTF-8] "java/lang/ClassCastException"
            // +   [CONSTANT_Class_info] for above
            // +   [UTF-8] "java/lang/NullPointerException"
            // +   [CONSTANT_Class_info] for above
            // +   [UTF-8] "java/lang/IllegalArgumentException"
            // +   [CONSTANT_Class_info] for above
            // +   [UTF-8] "java/lang/InvocationTargetException"
            // +   [CONSTANT_Class_info] for above
            // +   [UTF-8] "<init>"
            // +   [UTF-8] "()V"
            // +   [CONSTANT_NameAndType_info] for above
            // +   [CONSTANT_Methodref_info] for NullPointerException's constructor
            // +   [CONSTANT_Methodref_info] for IllegalArgumentException's constructor
            // +   [UTF-8] "(Ljava/lang/String;)V"
            // +   [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/String;)V"
            // +   [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String
            // +   [UTF-8] "(Ljava/lang/Throwable;)V"
            // +   [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/Throwable;)V"
            // +   [CONSTANT_Methodref_info] for InvocationTargetException's constructor
            // +   [CONSTANT_Methodref_info] for "super()"
            // +   [UTF-8] "java/lang/Object"
            // +   [CONSTANT_Class_info] for above
            // +   [UTF-8] "toString"
            // +   [UTF-8] "()Ljava/lang/String;"
            // +   [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;"
            // +   [CONSTANT_Methodref_info] for Object's toString method
            // +   [UTF-8] "Code"
            // +   [UTF-8] "Exceptions"
            //  *  [UTF-8] "java/lang/Boolean"
            //  *  [CONSTANT_Class_info] for above
            //  *  [UTF-8] "(Z)V"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "booleanValue"
            //  *  [UTF-8] "()Z"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "java/lang/Byte"
            //  *  [CONSTANT_Class_info] for above
            //  *  [UTF-8] "(B)V"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "byteValue"
            //  *  [UTF-8] "()B"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "java/lang/Character"
            //  *  [CONSTANT_Class_info] for above
            //  *  [UTF-8] "(C)V"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "charValue"
            //  *  [UTF-8] "()C"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "java/lang/Double"
            //  *  [CONSTANT_Class_info] for above
            //  *  [UTF-8] "(D)V"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "doubleValue"
            //  *  [UTF-8] "()D"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "java/lang/Float"
            //  *  [CONSTANT_Class_info] for above
            //  *  [UTF-8] "(F)V"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "floatValue"
            //  *  [UTF-8] "()F"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "java/lang/Integer"
            //  *  [CONSTANT_Class_info] for above
            //  *  [UTF-8] "(I)V"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "intValue"
            //  *  [UTF-8] "()I"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "java/lang/Long"
            //  *  [CONSTANT_Class_info] for above
            //  *  [UTF-8] "(J)V"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "longValue"
            //  *  [UTF-8] "()J"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "java/lang/Short"
            //  *  [CONSTANT_Class_info] for above
            //  *  [UTF-8] "(S)V"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
            //  *  [UTF-8] "shortValue"
            //  *  [UTF-8] "()S"
            //  *  [CONSTANT_NameAndType_info] for above
            //  *  [CONSTANT_Methodref_info] for above
    
            short numCPEntries = NUM_BASE_CPOOL_ENTRIES + NUM_COMMON_CPOOL_ENTRIES;
            boolean usesPrimitives = usesPrimitiveTypes();
            if (usesPrimitives) {
                numCPEntries += NUM_BOXING_CPOOL_ENTRIES;
            }
            if (forSerialization) {
                numCPEntries += NUM_SERIALIZATION_CPOOL_ENTRIES;
            }
    
            // Add in variable-length number of entries to be able to describe
            // non-primitive parameter types and checked exceptions.
            numCPEntries += (short) (2 * numNonPrimitiveParameterTypes());
    
            asm.emitShort(add(numCPEntries, S1));
    
            final String generatedName = generateName(isConstructor, forSerialization);
            asm.emitConstantPoolUTF8(generatedName);
            asm.emitConstantPoolClass(asm.cpi());
            thisClass = asm.cpi();
            if (isConstructor) {
                if (forSerialization) {
                    asm.emitConstantPoolUTF8
                        ("sun/reflect/SerializationConstructorAccessorImpl");
                } else {
                    asm.emitConstantPoolUTF8("sun/reflect/ConstructorAccessorImpl");
                }
            } else {
                asm.emitConstantPoolUTF8("sun/reflect/MethodAccessorImpl");
            }
            asm.emitConstantPoolClass(asm.cpi());
            superClass = asm.cpi();
            asm.emitConstantPoolUTF8(getClassName(declaringClass, false));
            asm.emitConstantPoolClass(asm.cpi());
            targetClass = asm.cpi();
            short serializationTargetClassIdx = (short) 0;
            if (forSerialization) {
                asm.emitConstantPoolUTF8(getClassName(serializationTargetClass, false));
                asm.emitConstantPoolClass(asm.cpi());
                serializationTargetClassIdx = asm.cpi();
            }
            asm.emitConstantPoolUTF8(name);
            asm.emitConstantPoolUTF8(buildInternalSignature());
            asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
            if (isInterface()) {
                asm.emitConstantPoolInterfaceMethodref(targetClass, asm.cpi());
            } else {
                if (forSerialization) {
                    asm.emitConstantPoolMethodref(serializationTargetClassIdx, asm.cpi());
                } else {
                    asm.emitConstantPoolMethodref(targetClass, asm.cpi());
                }
            }
            targetMethodRef = asm.cpi();
            if (isConstructor) {
                asm.emitConstantPoolUTF8("newInstance");
            } else {
                asm.emitConstantPoolUTF8("invoke");
            }
            invokeIdx = asm.cpi();
            if (isConstructor) {
                asm.emitConstantPoolUTF8("([Ljava/lang/Object;)Ljava/lang/Object;");
            } else {
                asm.emitConstantPoolUTF8
                    ("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
            }
            invokeDescriptorIdx = asm.cpi();
    
            // Output class information for non-primitive parameter types
            nonPrimitiveParametersBaseIdx = add(asm.cpi(), S2);
            for (int i = 0; i < parameterTypes.length; i++) {
                Class<?> c = parameterTypes[i];
                if (!isPrimitive(c)) {
                    asm.emitConstantPoolUTF8(getClassName(c, false));
                    asm.emitConstantPoolClass(asm.cpi());
                }
            }
    
            // Entries common to FieldAccessor, MethodAccessor and ConstructorAccessor
            emitCommonConstantPoolEntries();
    
            // Boxing entries
            if (usesPrimitives) {
                emitBoxingContantPoolEntries();
            }
    
            if (asm.cpi() != numCPEntries) {
                throw new InternalError("Adjust this code (cpi = " + asm.cpi() +
                                        ", numCPEntries = " + numCPEntries + ")");
            }
    
            // Access flags
            asm.emitShort(ACC_PUBLIC);
    
            // This class
            asm.emitShort(thisClass);
    
            // Superclass
            asm.emitShort(superClass);
    
            // Interfaces count and interfaces
            asm.emitShort(S0);
    
            // Fields count and fields
            asm.emitShort(S0);
    
            // Methods count and methods
            asm.emitShort(NUM_METHODS);
    
            emitConstructor();
            emitInvoke();
    
            // Additional attributes (none)
            asm.emitShort(S0);
    
            // Load class
            vec.trim();
            final byte[] bytes = vec.getData();
            // Note: the class loader is the only thing that really matters
            // here -- it's important to get the generated code into the
            // same namespace as the target class. Since the generated code
            // is privileged anyway, the protection domain probably doesn't
            // matter.
            return AccessController.doPrivileged(
                new PrivilegedAction<MagicAccessorImpl>() {
                    public MagicAccessorImpl run() {
                            try {
                            return (MagicAccessorImpl)
                            ClassDefiner.defineClass
                                    (generatedName,
                                     bytes,
                                     0,
                                     bytes.length,
                                     declaringClass.getClassLoader()).newInstance();
                            } catch (InstantiationException | IllegalAccessException e) {
                                throw new InternalError(e);
                            }
                        }
                    });
        }
    View Code

         咱们主要看这一句:ClassDefiner.defineClass(xx, declaringClass.getClassLoader()).newInstance();

         在ClassDefiner.defineClass方法实现中,每被调用一次都会生成一个DelegatingClassLoader类加载器对象 ,这里每次都生成新的类加载器,是为了性能考虑,在某些情况下可以卸载这些生成的类,因为类的卸载是只有在类加载器可以被回收的情况下才会被回收的,如果用了原来的类加载器,那可能导致这些新创建的类一直无法被卸载!

         而反射生成的类,有时候可能用了就可以卸载了,所以使用其独立的类加载器,从而使得更容易控制反射类的生命周期!

    最后,用几句话总结反射的实现原理:

        1. 反射类及反射方法的获取,都是通过从列表中搜寻查找匹配的方法,所以查找性能会随类的大小方法多少而变化;

        2. 每个类都会有一个与之对应的Class实例,从而每个类都可以获取method反射方法,并作用到其他实例身上;

        3. 反射也是考虑了线程安全的,放心使用;

        4. 反射使用软引用relectionData缓存class信息,避免每次重新从jvm获取带来的开销;

        5. 反射调用多次生成新代理Accessor, 而通过字节码生存的则考虑了卸载功能,所以会使用独立的类加载器;

        6. 当找到需要的方法,都会copy一份出来,而不是使用原来的实例,从而保证数据隔离;

        7. 调度反射方法,最终是由jvm执行invoke0()执行;

  • 相关阅读:
    ARM-Linux S5PV210 UART驱动(1)----用户手册中的硬件知识
    可变参数列表---以dbg()为例
    《C和指针》 读书笔记 -- 第7章 函数
    《Visual C++ 程序设计》读书笔记 ----第8章 指针和引用
    支持异步通知的globalfifo平台设备驱动程序及其测试代码
    linux内核中sys_poll()的简化分析
    《C和指针》读书笔记——第五章 操作符和表达式
    测试方法-等价类划分法
    MonkyTalk学习-8-Agent
    MonkyTalk学习-7-Verify-Verify
  • 原文地址:https://www.cnblogs.com/yougewe/p/10125073.html
Copyright © 2011-2022 走看看