动态代理的使用和实现机制
工作中很久没有接触动态代理,之前的学习也有些模糊,导致有些遗忘,这里记录下个人对动态代理的理解,如有读者发现问题多多指正吧。
就java而言对于动态代理的支持多是以接口实现,其实现主要是通过java.lang.reflect.Proxy类,java.lang.reflect.InvocationHandler接口。Proxy类主要用于获取动态代理对象,InvocationHandler接口用来约束调用者实现。
动态代理运行机制:
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法会返回一个代理对象类的实例。当程序执行时会通过反射机制动态的生成一个代理类,该类实现一个接口里的方法(也就是说代理类与被代理类有相同的接口),在该代理类里面有一个InvocationHandler类型的成员变量,也就是调用处理程序,通过调用处理程序来给被代理类增强功能。创建好代理类后就调用类加载器将该类加载到类存,然后再通过反射创建一个该代理类的实例对象。下面是具体实现:
1 1.代理接口:Moveable.java 2 3 package com.test; 4 5 public interface Moveable { 6 7 void move(); 8 9 } 10 11 12 2.被代理对象:Tank.java 13 package com.test; 14 15 import java.util.Random; 16 17 public class Tank implements Moveable { 18 19 public void move() { 20 System.out.println("Tank moving..."); 21 try { 22 Thread.sleep(new Random().nextInt(10000)); 23 } catch (InterruptedException e) { 24 e.printStackTrace(); 25 } 26 } 27 28 } 29 30 3.为被代理对象产生一个代理类对象,其中是想增加记录运行时间的功能 31 32 package com.test; 33 34 import java.io.File; 35 import java.io.FileWriter; 36 import java.lang.reflect.Constructor; 37 import java.lang.reflect.Method; 38 39 import javax.tools.JavaCompiler; 40 import javax.tools.StandardJavaFileManager; 41 import javax.tools.ToolProvider; 42 import javax.tools.JavaCompiler.CompilationTask; 43 44 public class Proxy { 45 public static Object newProxyInstance(Class interfaces,InvocationHandler h)throws Exception{ 46 StringBuffer methodStr = new StringBuffer(); 47 String tr = "\r\n"; 48 Method[] methods = interfaces.getMethods(); 49 //拼接代理类的方法 50 for (Method method : methods) { 51 methodStr.append( 52 " public "+ method.getReturnType()+ " " +method.getName()+"() {" + tr + 53 " try {" + tr + 54 " java.lang.reflect.Method md = " + interfaces.getName() + "." + "class.getMethod(\"" + method.getName() + "\");" + tr + 55 " h.invoke(this,md);" + tr + 56 " }catch(Exception e) {e.printStackTrace();}" + tr + 57 " }" + tr 58 ); 59 } 60 61 //拼接代理类 62 String src = "package com.test;" + tr + 63 "import com.test.Moveable;" + tr + 64 "public class TimeProxy implements " + interfaces.getName() + " {" + tr + 65 " private com.test.InvocationHandler h;" + tr + 66 " public TimeProxy(com.test.InvocationHandler h) {" + tr + 67 " this.h = h;" + tr + 68 " }" + tr + 69 methodStr.toString() + tr + 70 "}"; 71 //创建代理类 72 String fileName = System.getProperty("user.dir") + "/src/com/test/TimeProxy.java"; 73 File file = new File(fileName); 74 FileWriter writer = new FileWriter(file); 75 writer.write(src); 76 writer.flush(); 77 writer.close(); 78 //编译 79 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 80 StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null); 81 Iterable units = fileMgr.getJavaFileObjects(fileName); 82 CompilationTask ct = compiler.getTask(null, fileMgr, null, null, null, units); 83 ct.call(); 84 fileMgr.close(); 85 //加载类到内存: 86 Class c = ClassLoader.getSystemClassLoader().loadClass("com.test.TimeProxy"); 87 Constructor constructor = c.getConstructor(InvocationHandler.class); //得到参数为InvocationHandler类型的构造方法 88 Object m = constructor.newInstance(h); //通过该构造方法得到实例 89 return m; 90 91 } 92 } 93 94 4.TankProxy.java 95 96 package com.test; 97 98 import java.lang.reflect.Method; 99 100 public class TankProxy { 101 public static <T> T getBean(final Object tank) throws Exception{ 102 return (T)Proxy.newProxyInstance(tank.getClass().getInterfaces()[0], new InvocationHandler(){ 103 public void invoke(Object proxy, Method method) { 104 long start = System.currentTimeMillis(); 105 System.out.println("start:"+start); 106 try { 107 method.invoke(tank, new Object[]{}); 108 } catch (Exception e) { 109 e.printStackTrace(); 110 } 111 long end = System.currentTimeMillis(); 112 System.out.println("end:"+end); 113 System.out.println("time:"+(end-start)); 114 } 115 116 }); 117 } 118 } 119 120 5.测试程序: 121 122 package com.test; 123 124 import java.util.List; 125 126 import com.extend.Tank2; 127 import com.extend.Tank3; 128 import com.juhe.LogProxy; 129 import com.juhe.TimeProxy; 130 131 public class Test { 132 public static void main(String[] args) throws Exception { 133 Tank tank = new Tank(); 134 Moveable m = TankProxy.getBean(tank); 135 m.move(); 136 137 } 138 139 } 140 141 142 143 执行该程序的结果为: 144 start:1369121253400 145 Tank moving... 146 end:1369121260078 147 time:6678 148 149 150 151 动态生成的代理类的内容如下: 152 153 package com.test; 154 import com.test.Moveable; 155 public class TimeProxy implements com.test.Moveable { 156 private com.test.InvocationHandler h; 157 public TimeProxy(com.test.InvocationHandler h) { 158 this.h = h; 159 } 160 public void move() { 161 try { 162 java.lang.reflect.Method md = com.test.Moveable.class.getMethod("move"); 163 h.invoke(this,md); 164 }catch(Exception e) {e.printStackTrace();} 165 } 166 167 }
小结:动态代理在运行期通过接口动态生成代理类,这为其带来了一定的灵活性,但这个灵活性却带来了两个问题,第一代理类必须实现一个接口,如果没实现接口会抛出一个异常。第二性能影响,因为动态代理使用反射的机制实现的,首先反射肯定比直接调用要慢,其次使用反射大量生成类文件可能引起Full GC造成性能影响,因为字节码文件加载后会存放在JVM运行时区的方法区(或者叫持久代)中,当方法区满的时候,会引起Full GC,所以当你大量使用动态代理时,可以将持久代设置大一些,减少Full GC次数。
引用前者:残剑
转载于:https://www.cnblogs.com/ldy-blogs/p/8480059.html
动态代理的使用和实现机制相关推荐
- 动态代理/spring IOC/JAVA反射机制
动态代理 代理的作用就是控制对象的访问权限: 首先我们需要写一个接口 这个就是代理接口 public interface Student { public void S1(); } 然后在写一个接口的 ...
- Java 动态代理机制分析及扩展--转
http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/#icomments http://www.ibm.com/developerworks/c ...
- Java 动态代理机制分析及扩展,第 1 部分
引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执 ...
- Java 动态代理机制分析及扩展
简介: 本文通过分析 Java 动态代理的机制和特点,解读动态代理类的源代码,并且模拟推演了动态代理类的可能实现,向读者阐述了一个完整的 Java 动态代理运作过程,希望能帮助读者加深对 Java 动 ...
- Java进阶 | Proxy动态代理机制详解
一.Jvm加载对象 在说Java动态代理之前,还是要说一下Jvm加载对象的过程,这个依旧是理解动态代理的基础性原理: Java类即源代码程序.java类型文件,经过编译器编译之后就被转换成字节代码.c ...
- 深度剖析JDK动态代理机制
摘要 相比于静态代理,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定一组接口及目标类对象就能动态的获得代理对象. 代理模式 使用代理模式必须要让代理类和目标类实现相同的接口,客户端通过 ...
- 【Java 19】反射 - 反射机制概述、获取Class实例、类的加载与ClassLoader的理解、创建运行时类的对象、获取运行时类的完整结构、调用运行时类的指定结构、动态代理
反射机制概述.获取Class实例.类的加载与ClassLoader的理解.创建运行时类的对象.获取运行时类的完整结构.调用运行时类的指定结构.动态代理 反射 1 Java反射机制概述 1.1 Java ...
- 动态代理竟然如此简单!
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 这篇文章我们来聊一下 Java 中的动态代理. 动态代理在 ...
- Java代理系列-动态代理
2019独角兽企业重金招聘Python工程师标准>>> 动态代理可以做什么?比如说spring的AOP,它就是以动态代理为基础实现的,AOP拦截需要的请求,然后通过代理把请求的结果返 ...
最新文章
- Ubuntu 14.04安装搜狗拼音linux版应该注意的问题
- 跨浏览器开发经验总结(三)
- wegame饥荒一直连接中_23万人捧场热血传奇怀旧版,WeGame拯救计划,前景如何?...
- 基于Base64的图片转字符串-java和C#互通问题
- 隐马尔科夫模型HMM自学 (3)
- 【前端面试】数据类型与类型检测
- 包治百病 | 如何将一个.NET Core类库发布到NuGet
- windows10中远程访问凭据不工作
- 邮票的孔怎么做出来的_金银花茶是怎么做出来的呢
- java多态与对象转型
- HDU X问题 中国剩余定理--求满足条件的个数
- Python学习 :文件操作
- 《System语言详解》——3. SystemTap脚本的各大组件
- SylixOS armv8 任务切换
- [Golang]解决Map的并发性问题:sync.Map
- 手机利用NFC功能复制门禁卡到小米手环上
- 时点数列序时平均数_由时点数列计算序时平均数.ppt
- 2020年复旦电子信息专硕复试经验分享
- Weighted Graphs最短路径算法理解
- html图片不能拖动,关于html5图片拖动的代码的问题?
热门文章
- 仿哔哩哔哩动画Android客户端(哔哩哔哩 (゜-゜)つロ 干杯~-bilibili)
- RelativeLayout里各个控件的相对位置
- 基于扩展卡尔曼滤波EKF和模型预测控制MPC,自动泊车场景建模开发
- JfreeChart图表
- 龙华区民治街道上塘片区旧改——华润
- fullcalendar使用
- 蓝桥杯试题 基础练习 十进制转十六进制
- 选公司,就要去上升期的!
- The 2021 ICPC Asia Taipei Regional Programming Contest L. Leadfoot(组合数学/2-adic赋值函数+kummer定理)
- 银行家算法-C语言实现