反射原理之源码

本文基于 Java 11 源码进行讲解,不同版本可能会有些许区别

方法一:forName

forName 方法有三个重载(一个是 Java 9 后再引入的,此处不讨论)

  • forName(String)

    public static Class<?> forName(String className) throws ClassNotFoundException {
        // 获得调用方法的类
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }
    

    跟踪进 forName0 方法进入如下

    /** Called after security check for system loader access checks have been made. */
    private static native Class<?> forName0(String name, boolean initialize,
                                            ClassLoader loader,
                                            Class<?> caller)
        throws ClassNotFoundException;
    

    可见 forName0 方法是一个本地方法,有JVM虚拟机做具体实现

  • forName(String, boolean, ClassLoader)

    public static Class<?> forName(String name, boolean initialize, ClassLoader loader)
        throws ClassNotFoundException {
    	Class<?> caller = null;
        // 检查是否有权限通过类加载器获取类(此处与私有方法无关,是由 SecurityManager 所控制的,后文亦如此)
    	SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
         	caller = Reflection.getCallerClass();
            if (loader == null) {
    			ClassLoader ccl = ClassLoader.getClassLoader(caller);
    			if (ccl != null) {
    				sm.checkPermission(
    					SecurityConstants.GET_CLASSLOADER_PERMISSION);
    			}
    		}
    	}
        // 通过调用本地方法获得类,见上条
    	return forName0(name, initialize, loader, caller);
    }
    

    有参数可知,在反射的 forName 方法中是可以选择不初始化类的

方法二:getDeclareMethods

public Method[] getDeclaredMethods() throws SecurityException {
	// 检测是否有权限获取类方法
	SecurityManager sm = System.getSecurityManager();
	if (sm != null) {
		checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
	}
	// 见下讲解
	return copyMethods(privateGetDeclaredMethods(false));
}

​ 可以看到,返回值是经过 privateGetDeclaredMethods(false) 取得结果传入 copyMethods(Method[]) 再返回的,首先我们先跟踪进 privateGetDeclaredMethods(boolean)

// 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) {
 	Method[] res;
    // 见下讲解
	ReflectionData<T> rd = reflectionData();
    
	···
}

​ 从方法开始的注释可以看出,privateGetDeclaredMethods 返回的方法是根(root)方法,所得对象不能被暴露在外面,必须经过复制。(具体原因见后文)

​ 可以看到,程序通过 reflectionData() 方法获得 ReflectionData 实例,跟踪进 reflectionData

​ 注:ReflectionData 类是 Class 类的一个内部类

// Lazily create and cache ReflectionData
private ReflectionData<T> reflectionData() {
    // 获取对 reflectionData 的缓存,此处为软引用,内存不足时引用会被清理
	SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;
    // 见下讲解
	int classRedefinedCount = this.classRedefinedCount;
	ReflectionData<T> rd;
	if (reflectionData != null && (rd = reflectionData.get()) != null &&
        	rd.redefinedCount == classRedefinedCount) {
		return rd;
	}
	// 没有缓存过或者引用的对象过期了
	return newReflectionData(reflectionData, classRedefinedCount);
}

​ 首先先看一下 classRedefinedCount 的定义

// Incremented by the VM on each call to JVM TI RedefineClasses()
// that redefines this class or a superclass.
private transient volatile int classRedefinedCount;

​ 通过源码的注释,我们可以知道这个 classRedefinedCount 是 JVM 内部一个用于标记类是否过期的一个标签。

​ 这样我们再看回 reflectionData() 方法,通过对缓存的对象的标签与 JVM 内部标签的比较来确定是否过期,如果过期或者压根没有缓存就生成一个新的对象。

​ 我们跟踪进 newReflectionData(SoftReference<ReflectionData<T>>, int classRedefinedCount)

private ReflectionData<T> newReflectionData(
	    SoftReference<ReflectionData<T>> oldReflectionData, int classRedefinedCount) {
	while (true) {
		ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount);
		// 通过乐观锁去获得数据
		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;
		}
	}
}

​ 至此我们已经可以获得到一个可用的 ReflectionData<T> 对象,我们回到 ``privateGetDeclaredMethods(boolean)` 的源码

private Method[] privateGetDeclaredMethods(boolean publicOnly) {
 	Method[] res;
	ReflectionData<T> rd = reflectionData();
	if (rd != null) {
		res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
        // 判断是否已经缓存过
		if (res != null) return res;
	}
	// 未缓存过,从虚拟机获取结果
	res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
	if (rd != null) {
        // 对结果进行缓存
		if (publicOnly) {
			rd.declaredPublicMethods = res;
		} else {
			rd.declaredMethods = res;
		}
	}
	return res;
}

​ 通过 privateGetDeclaredMethods(boolean) 获得到了所谓的根(root)方法,按照源码下一步进入到了copyMethods(Method[]) 的实现

private static Method[] copyMethods(Method[] arg) {
	Method[] out = new Method[arg.length];
	ReflectionFactory fact = getReflectionFactory();
	for (int i = 0; i < arg.length; i++) {
		out[i] = fact.copyMethod(arg[i]);
	}
	return out;
}

copyMethods(Method[]) 的实现很简单,就是通过调用 ReflectionFactory.copyMethod(Method) 方法对传入的 arg 参数进行深拷贝

public Method copyMethod(Method arg) {
	return langReflectAccess().copyMethod(arg);
}

​ 而 ReflectionFactory.copyMethod(Method) 方法仅仅调用了 langReflectAccess().copyMethod(Method)

public Method copyMethod(Method arg) {
	return arg.copy();
}

langReflectAccess().copyMethod(Method) 方法则调用了 arg 参数自身的 copy() 方法

Method copy() {
	// This routine enables sharing of MethodAccessor objects
	// among Method 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 Method");
	
	Method res = new Method(clazz, name, parameterTypes, returnType,
                                exceptionTypes, modifiers, slot, signature,
                                annotations, parameterAnnotations, annotationDefault);
	res.root = this;
	res.methodAccessor = methodAccessor;
	return res;
}

Method.copy() 的实现也只是对 Method 对象进行了深拷贝,但从注释中我们却可以知道为什么 Java 要如此大费周章的进行拷贝。

​ 每一个 Method 对象都继承了 AccessibleObject 类对类对象各种方法和域访问权限的控制,由于 AccessibleObject 类要求了每一个 Method 对象(可以是同一方法)的访问权限必须相对独立,所以为了避免后续 Method 对象的权限在外部被调用设置可访问性(如对 JavaBean 的填充不应填充完一个实例以后的所有实例的私有域都默认变成可访问的)不相互影响,需要每次获取 Method 对象时进行深拷贝。

方法三: newInstance

​ 此处需要注意的是,Class 类的 newInstance() 方法在 Java 9 时就被废弃了,取而代之的是通过手动获取构造器来,在 Constructor 对象上进行 newInstance() 。(因为可以直接把构造器私有检测交给调用方)

@Deprecated(since="9")
public T newInstance() throws InstantiationException, IllegalAccessException
{
	// 检测是否有权限获得构造器
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), false);
    }

    // NOTE: the following code may not be strictly correct under
    // the current Java memory model.

    // 查找默认无参构造器
    if (cachedConstructor == null) {
    	// 不能对 Class 类进行实例化
        if (this == Class.class) {
            throw new IllegalAccessException(
                "Can not call newInstance() on the Class for java.lang.Class"
            );
        }
        try {
            Class<?>[] empty = {};
            // 获得无参构造器并进行深拷贝,原因见 getDeclareMethods 一节
            final Constructor<T> c = getReflectionFactory().copyConstructor(
                                        getConstructor0(empty, Member.DECLARED));
            // 禁用可访问性检测
            java.security.AccessController.doPrivileged(
                new java.security.PrivilegedAction<>() {
                    public Void run() {
                        c.setAccessible(true);
                        return null;
                    }
                });
            cachedConstructor = c;
        } catch (NoSuchMethodException e) {
            throw (InstantiationException) 
            		new InstantiationException(getName()).initCause(e);
        }
    }
    Constructor<T> tmpConstructor = cachedConstructor;
    // 安全性检测
    Class<?> caller = Reflection.getCallerClass();
    if (newInstanceCallerCache != caller) {
    	// 对构造器的可访问性进行检测(构造器私有在此检测)
        int modifiers = tmpConstructor.getModifiers();
        Reflection.ensureMemberAccess(caller, this, this, modifiers);
        newInstanceCallerCache = caller;
    }
    // 执行构造器
    try {
        return tmpConstructor.newInstance((Object[])null);
    } catch (InvocationTargetException e) {
        Unsafe.getUnsafe().throwException(e.getTargetException());
        // 无法到达,为了通过编译,因为在上一方法一定会抛出错误,打断程序执行
        return null;
    }
}

​ 经过获取无参构造器及可访问性检测,进入到了构造器的 newInstance() 方法

public T newInstance(Object ... initargs)
		throws InstantiationException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException {
	// 非重载构造器,检测可访问性
    if (!override) {
        Class<?> caller = Reflection.getCallerClass();
        checkAccess(caller, clazz, clazz, modifiers);
    }
    // 对于枚举类,禁止实例化
    if ((clazz.getModifiers() & Modifier.ENUM) != 0)
        throw new IllegalArgumentException("Cannot reflectively create enum objects");
    // 获取构造器访问器
    ConstructorAccessor ca = constructorAccessor;  // 原子操作
    if (ca == null) {
        // 未缓存
        ca = acquireConstructorAccessor();
    }
    @SuppressWarnings("unchecked")
    // 最后调用本地方法完成实例化
    T inst = (T) ca.newInstance(initargs);
    return inst;
}  

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值