Java反射
2019-01-21 02:40:32来源:博客园 阅读 ()
Java反射机制在程序运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态的获取信息以及动态调用对象的方法 的功能称为java的反射机制。
首先你需要了解类加载的过程,这里我们简单提一下(加载-验证-准备-解析-初始化),反射是靠JVM和Class相关类实现的。
按照这个例子,我们调试下看看具体实现。
@Data public class Person { private String name; public static void main(String[] args) throws Exception { Person person = new Person(); person.setName("lewis"); for (int i = 0; i < 16; i++) { Method method = Person.class.getMethod("getName"); System.out.println(method.invoke(person)); } } }
@CallerSensitive public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { // 检查方法是否为public if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); // 权限校验 checkAccess(caller, clazz, obj, modifiers); } } // MethodAccessor实现有两个版本,一个是Java实现的,另一个是JNI实现的 MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args); }
我们上面提到了 MethodAccessor 有两个实现,Java版本和JNI版本(就是java native),
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; } }
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; } }
来看看NativeMethodAccessorImpl实现,超过15次以后调用反射,就会通过我们上面提到的中间层 DelegatingMethodAccessorImpl 所引用的 MethodAccessor 都是java 版。
class NativeMethodAccessorImpl extends MethodAccessorImpl { private final Method method; private DelegatingMethodAccessorImpl parent; private int numInvocations; NativeMethodAccessorImpl(Method var1) { this.method = var1; } public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException { // 方法被调用时,程序调用计数器都会增加1,看看是否超过阈值 if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) { // 超过15次 则调用MethodAccessorGenerator.generateMethod()来生成Java版的MethodAccessor的实现类 // 并且改变通过中间层,后续DelegatingMethodAccessorImpl所引用的MethodAccessor改为Java版 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版本,JNI方式调用 return invoke0(this.method, var1, var2); } void setParent(DelegatingMethodAccessorImpl var1) { this.parent = var1; } private static native Object invoke0(Method var0, Object var1, Object[] var2); }
在默认情况下,方法的反射调用为委派实现,委派给本地实现来进行方法调用。在调用超过 15 次之后,委派实现便会将委派对象切换至动态实现。这个动态的字节码是在Java运行过程中通过ASM自动生成的,它将直接使用 invoke 指令来调用目标方法。
继续查看代码,可以看到sun.reflect.MethodAccessorGenerator#generate
的实现是调用asm字节码增强工具来生成类,此过程较长,不在此列出。在该方法的最后,我们发现有这样一个操作sun.reflect.ClassDefiner#defineClass
,查看其源码
static Class<?> defineClass(String name, byte[] bytes, int off, int len, final ClassLoader parentClassLoader) { // 创建一个DelegatingClassLoader用来加载生成的类 ClassLoader newLoader = AccessController.doPrivileged( new PrivilegedAction<ClassLoader>() { public ClassLoader run() { return new DelegatingClassLoader(parentClassLoader); } }); return unsafe.defineClass(name, bytes, off, len, newLoader, null); }
参考:
一个关于log4j2的高并发问题
原文链接:https://www.cnblogs.com/lewis09/p/10288854.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- 国外程序员整理的Java资源大全(全部是干货) 2020-06-12
- 2020年深圳中国平安各部门Java中级面试真题合集(附答案) 2020-06-11
- 2020年java就业前景 2020-06-11
- 04.Java基础语法 2020-06-11
- Java--反射(框架设计的灵魂)案例 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash