深入理解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()执行;