一、反射的用法
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
对这两个字段重新设置,而且只会设置一次;
如果noInflation
为false
,方法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
对象就是一个代理对象,负责调用被代理对象delegate
的invoke
方法,其中delegate
参数目前是NativeMethodAccessorImpl
对象,所以最终Method
的invoke
方法调用的是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?
原文地址:https://www.cnblogs.com/aiqiqi/p/10691116.html