工作中很久没有接触动态代理,之前的学习也有些模糊,导致有些遗忘,这里记录下个人对动态代理的理解,如有读者发现问题多多指正吧。

就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

动态代理的使用和实现机制相关推荐

  1. 动态代理/spring IOC/JAVA反射机制

    动态代理 代理的作用就是控制对象的访问权限: 首先我们需要写一个接口 这个就是代理接口 public interface Student { public void S1(); } 然后在写一个接口的 ...

  2. Java 动态代理机制分析及扩展--转

    http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/#icomments http://www.ibm.com/developerworks/c ...

  3. Java 动态代理机制分析及扩展,第 1 部分

    引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执 ...

  4. Java 动态代理机制分析及扩展

    简介: 本文通过分析 Java 动态代理的机制和特点,解读动态代理类的源代码,并且模拟推演了动态代理类的可能实现,向读者阐述了一个完整的 Java 动态代理运作过程,希望能帮助读者加深对 Java 动 ...

  5. Java进阶 | Proxy动态代理机制详解

    一.Jvm加载对象 在说Java动态代理之前,还是要说一下Jvm加载对象的过程,这个依旧是理解动态代理的基础性原理: Java类即源代码程序.java类型文件,经过编译器编译之后就被转换成字节代码.c ...

  6. 深度剖析JDK动态代理机制

    摘要 相比于静态代理,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定一组接口及目标类对象就能动态的获得代理对象. 代理模式 使用代理模式必须要让代理类和目标类实现相同的接口,客户端通过 ...

  7. 【Java 19】反射 - 反射机制概述、获取Class实例、类的加载与ClassLoader的理解、创建运行时类的对象、获取运行时类的完整结构、调用运行时类的指定结构、动态代理

    反射机制概述.获取Class实例.类的加载与ClassLoader的理解.创建运行时类的对象.获取运行时类的完整结构.调用运行时类的指定结构.动态代理 反射 1 Java反射机制概述 1.1 Java ...

  8. 动态代理竟然如此简单!

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 这篇文章我们来聊一下 Java 中的动态代理. 动态代理在 ...

  9. Java代理系列-动态代理

    2019独角兽企业重金招聘Python工程师标准>>> 动态代理可以做什么?比如说spring的AOP,它就是以动态代理为基础实现的,AOP拦截需要的请求,然后通过代理把请求的结果返 ...

最新文章

  1. Ubuntu 14.04安装搜狗拼音linux版应该注意的问题
  2. 跨浏览器开发经验总结(三)
  3. wegame饥荒一直连接中_23万人捧场热血传奇怀旧版,WeGame拯救计划,前景如何?...
  4. 基于Base64的图片转字符串-java和C#互通问题
  5. 隐马尔科夫模型HMM自学 (3)
  6. 【前端面试】数据类型与类型检测
  7. 包治百病 | 如何将一个.NET Core类库发布到NuGet
  8. windows10中远程访问凭据不工作
  9. 邮票的孔怎么做出来的_金银花茶是怎么做出来的呢
  10. java多态与对象转型
  11. HDU X问题 中国剩余定理--求满足条件的个数
  12. Python学习 :文件操作
  13. 《System语言详解》——3. SystemTap脚本的各大组件
  14. SylixOS armv8 任务切换
  15. [Golang]解决Map的并发性问题:sync.Map
  16. 手机利用NFC功能复制门禁卡到小米手环上
  17. 时点数列序时平均数_由时点数列计算序时平均数.ppt
  18. 2020年复旦电子信息专硕复试经验分享
  19. Weighted Graphs最短路径算法理解
  20. html图片不能拖动,关于html5图片拖动的代码的问题?

热门文章

  1. 仿哔哩哔哩动画Android客户端(哔哩哔哩 (゜-゜)つロ 干杯~-bilibili)
  2. RelativeLayout里各个控件的相对位置
  3. 基于扩展卡尔曼滤波EKF和模型预测控制MPC,自动泊车场景建模开发
  4. JfreeChart图表
  5. 龙华区民治街道上塘片区旧改——华润
  6. fullcalendar使用
  7. 蓝桥杯试题 基础练习 十进制转十六进制
  8. 选公司,就要去上升期的!
  9. The 2021 ICPC Asia Taipei Regional Programming Contest L. Leadfoot(组合数学/2-adic赋值函数+kummer定理)
  10. 银行家算法-C语言实现