深入理解JAVA反射

深入理解JAVA反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

下面是反射的一段简单的使用

public class Relections {
    public static void main(String[] args) throws Exception {
		//获取Class的三种方法
        //在这里会去利用ClassLoader装载我们的Class
        Class<?> class1 = Class.forName("com.test.test.design.observer.Subject");
        Class<Subject> class2 = Subject.class;
        
        Subject subject = (Subject)class1.newInstance();
        
        Class<? extends Subject> class3 = subject.getClass();

        Method method = subject.getClass().getMethod("getState");

        method.invoke(subject);

    }
}

这段代码会去调用我们的Subject类的getState()方法

然后我们来对这些代码进行解析,反射的源码很多都是本地方法,这里不会对本地方法进行解析,只会对java部分的源码进行讲解,推荐进行断点调试,否则不清楚运行到哪里

然后先来看张图
在这里插入图片描述

首先是对Class.forName()进行解析

Class.ForName()
	@CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        //调用本地方法,这里会跳到我们的ClassLoader.loadClass()方法中
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }
ClassLoader.loadClass()
	protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
    	//加锁
        synchronized (getClassLoadingLock(name)) {
            //检查是不是已经被加载过了
            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) {
                    
                }

                if (c == null) {
                    
                    long t1 = System.nanoTime();
                    //加载类,子类重写的方法
                    c = findClass(name);
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            //返回加载过的Class对象
            return c;
        }
    }

从上面看出,我们的Class.forName()主要是加载我们的类

  • 利用ClassLoader去loadClass()
  • 先交给父类尝试加载
  • 不行的话自己加载并返回

然后是我们的newInstance()方法

newInstance()
	@CallerSensitive
    public T newInstance()
        throws InstantiationException, IllegalAccessException
    {
        if (System.getSecurityManager() != null) {
            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
        }

        if (cachedConstructor == null) {
            if (this == Class.class) {
                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);
                
                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;
        
        int modifiers = tmpConstructor.getModifiers();
        if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            if (newInstanceCallerCache != caller) {
                Reflection.ensureMemberAccess(caller, this, null, modifiers);
                newInstanceCallerCache = caller;
            }
        }

        try {
        	//调用我们的构造器
            return tmpConstructor.newInstance((Object[])null);
        } catch (InvocationTargetException e) {
            Unsafe.getUnsafe().throwException(e.getTargetException());
            return null;
        }
    }
	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())) {
                //利用ReflectionFactory来copy一份我们的构造器返回                
                return getReflectionFactory().copyConstructor(constructor);
            }
        }
        throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
    }
	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;
    }
	//获取到我们所有的构造器
	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;
        }
        //没有缓存,
        if (isInterface()) {
            @SuppressWarnings("unchecked")
            Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0];
            res = temporaryRes;
        } else {
        	//JVM加载我们的构造器
            res = getDeclaredConstructors0(publicOnly);
        }
        if (rd != null) {
        	
        	//将我们的构造器存入到缓存中
            if (publicOnly) {
                rd.publicConstructors = res;
            } else {
                rd.declaredConstructors = res;
            }
        }
        return res;
    }
	private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData,
                                                int classRedefinedCount) {
        if (!useCaches) return null;

        while (true) {
            ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount);
            // 尝试去CAS修改
            if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) {
                return rd;
            }
            oldReflectionData = this.reflectionData;
            classRedefinedCount = this.classRedefinedCount;
            if (oldReflectionData != null &&
                (rd = oldReflectionData.get()) != null &&
                rd.redefinedCount == classRedefinedCount) {
                return rd;
            }
        }
    }

上面这段代码可以解释我们的反射为什么是线程安全的
1、CAS配上重试来保证我们的线程安全
2、对于构造器,会利用ReflectionFactory来拷贝一份供于使用

然后是我们和反射的一个重要的类ReflectionData,我们的Class中,包含了一个ReflectionData对象,这个对象里面包含了我们的对象的所有需要的东西,我们可以直接去获取,在Class中,这个类被软引用类型包装,作为缓存
private volatile transient SoftReference<ReflectionData<T>> 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;

        final int redefinedCount;

        ReflectionData(int redefinedCount) {
            this.redefinedCount = redefinedCount;
        }
    }

关于构造器最后的执行,也是基于本地方法来进行实现的
来总结下newInstance()步骤

  • 如果是Class类型的newInstance(),抛出异常
  • 尝试从ReflectionData软引用缓存中获取构造器的集合
  • 如果没有缓存,会利用CAS+重试保证线程安全
  • 如果缓存中没有,使用JVM去加载,并且放入到我们的缓存中
  • 然后遍历我们所有的构造器,并且比较构造器与我们需要的构造器的参数类型是不是一样的
  • 一样的话就会利用ReflectionFactory去拷贝一份构造器,然后返回
  • 最后会利用本地方法去执行构造器

然后来介绍方法的执行

	@CallerSensitive
    public Method getMethod(String name, Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException {
        //检查权限
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
        //获取方法
        Method method = getMethod0(name, parameterTypes, true);
        if (method == null) {
            throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
        }
        return method;
    }
	private Method getMethod0(String name, Class<?>[] parameterTypes, boolean includeStaticMethods) {
        MethodArray interfaceCandidates = new MethodArray(2);
        //获取方法
        Method res =  privateGetMethodRecursive(name, parameterTypes, includeStaticMethods, interfaceCandidates);
        if (res != null)
            return res;

        
        interfaceCandidates.removeLessSpecifics();
        return interfaceCandidates.getFirst(); // may be null
    }
	private Method privateGetMethodRecursive(String name,
            Class<?>[] parameterTypes,
            boolean includeStaticMethods,
            MethodArray allInterfaceCandidates) {
        Method res;
        
        if ((res = searchMethods(privateGetDeclaredMethods(true),
                                 name,
                                 parameterTypes)) != null) {
            if (includeStaticMethods || !Modifier.isStatic(res.getModifiers()))
                return res;
        }
        
        if (!isInterface()) {
            Class<? super T> c = getSuperclass();
            if (c != null) {
                if ((res = c.getMethod0(name, parameterTypes, true)) != null) {
                    return res;
                }
            }
        }
        
        Class<?>[] interfaces = getInterfaces();
        for (Class<?> c : interfaces)
            if ((res = c.getMethod0(name, parameterTypes, false)) != null)
                allInterfaceCandidates.add(res);
        // Not found
        return null;
    }
	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;
        }
        //没有的话就会利用JVM去进行加载
        res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
        //加入到缓存
        if (rd != null) {
            if (publicOnly) {
                rd.declaredPublicMethods = res;
            } else {
                rd.declaredMethods = res;
            }
        }
        return res;
    }

和构造器的基本一致,都是先去缓存中查找,没有的话就去JVM中加载,然后添加到缓存中,不过,方法会多一个filter的方法,但是我们重点关注外面的search的一个方法,这个方法会用来过滤方法名以及参数

	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;
        }
		//最后利用我们的依旧是利用ReflectionFactory来创建一个副本返回
        return (res == null ? res : getReflectionFactory().copyMethod(res));
    }

上面就是获取我们的方法,基本步骤和我们的构造器一致,然后是方法的执行

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) {
        	//创建我们的MethodAccessor
            ma = acquireMethodAccessor();
        }
        //进行执行的时候,是利用MethodAccessor进行调用,
        return ma.invoke(obj, args);
    }
	private MethodAccessor acquireMethodAccessor() {
        MethodAccessor tmp = null;
        if (root != null) tmp = root.getMethodAccessor();
        if (tmp != null) {
      		// 存在缓存时,存入 methodAccessor,否则调用 ReflectionFactory 创建新的 MethodAccessor
            methodAccessor = tmp;
        } else {
            // 否则,创建一个并且放到root中
            tmp = reflectionFactory.newMethodAccessor(this);
            setMethodAccessor(tmp);
        }

        return tmp;
    }

然后利用MethodAccessor来进行执行方法,先执行DelegatingMethodAccessorImpl,然后委托给我们的NativeMethodAccessorImpl来进行调用,但是,如果这个被调用的次数大于了15次,就会利用MethodAccessorGenerator来创建一个新的MethodAccessor来进行运行
这个是在我们的NativeMethodAccessorImpl中的invoke方法,这里会判断是不是超过阈值,然后创建一个新的一个MethodAccessor,并且修改Delegating中的属性,然后再去执行,替换掉我们的原来的NativeMethodAccessor
这里就是我们的Inflation机制,因为Native 版本一开始启动快,但是随着运行时间边长,速度变慢。Java 版本一开始加载慢,但是随着运行时间边长,速度变快。正是因为两种存在这些问题,所以第一次加载的时候我们会发现使用的是 NativeMethodAccessorImpl 的实现,而当反射调用次数超过 15 次之后,则使用 MethodAccessorGenerator 生成的 MethodAccessorImpl 对象去实现反射。

	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);
    }
	public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        return this.delegate.invoke(var1, var2);
    }

	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);
        }
		
		//native方法
        return invoke0(this.method, var1, var2);
    }

在我们的generateMethod中,会一直往里面调用

	return (MagicAccessorImpl)AccessController.doPrivileged(new PrivilegedAction<MagicAccessorImpl>() {
                public MagicAccessorImpl run() {
                    try {
                    	//重点
                        return (MagicAccessorImpl)ClassDefiner.defineClass(var13, var17, 0, var17.length, var1.getClassLoader()).newInstance();
                    } catch (IllegalAccessException | InstantiationException var2) {
                        throw new InternalError(var2);
                    }
                }
            });
ClassDefiner.defineClass()
	static Class<?> defineClass(String var0, byte[] var1, int var2, int var3, final ClassLoader var4) {
        ClassLoader var5 = (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
            public ClassLoader run() {
            	//每一次都会创建一个DelegatingClassLoader对象
                return new DelegatingClassLoader(var4);
            }
        });
        return unsafe.defineClass(var0, var1, var2, var3, var5, (ProtectionDomain)null);
    }

为什么每次都要new一个类加载器呢?
因为类的卸载需要类加载器被回收之后,才能进行回收,
如果反射的类和我们其他的类使用同一个类加载器,那么会很久都等不到回收
但是我们反射的类可能只会使用一下,之后就不再使用
所以使用独立的类加载器,可以更好的控制反射类的生命周期

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

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

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

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

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

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

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值