Java-马士兵动态代理模式

模拟jdk的动态代理的实现原理, 这些东西没有必要写出来,写项目的时候一般用不上,主要是为了面试和理解原理;

java动态代理有什么作用

作用非常大,在很多底层框架中都会用得到,比如struts,Spring等都用到了动态代理,它的作用很简单,就是将你要使用的类,重新生成一个子类或本类,这样框架就可以利用这个新生成的类做一些事情,比如在该类的方法前后加一些代码。。
这样的话,你想像一下,你是不是不用修改任何已经编写好的代码,只要使用代理就可以灵活的加入任何东西,将来不喜欢了,不用也不会影响原来的代码。

https://www.zhihu.com/question/20794107/answer/23334315

代理模式-聚合与继承方式比较

参考地址:http://www.cnblogs.com/shamgod/p/4591782.html

 

一、概述

1.目标:要在Tank的move()方法做时间代理及日志代理(可以设想以后还要增加很多代理处理),且代理间的顺序可活更换

2.思路:

(1)聚合:代理类聚合了被代理类,且代理类及被代理类都实现了movable接口,则可实现灵活多变,具体看代码

(2)继承:继承不够灵活,具体看代码

 
 

二、代码

1.Movable.java

2.Tank.java

3.TankTimeProxy.java

4.TankLogProxy.java

5.Tank2Time.java

6.Tank3Log.java

7.Client.java

 1.Movable.java

  1. public
    interface Movable {
  2.   public
    void move();
  3.  }

 
 

2.Tank.java

  1. import java.util.Random;
  2.  
  3. public
    class Tank implements Movable {
  4.  
  5.     @Override
  6.     public
    void move() {
  7.         System.out.println("Tank moving.......");
  8.         try {
  9.             Thread.sleep(new Random().nextInt(5000));
  10.         } catch (InterruptedException e) {
  11.             e.printStackTrace();
  12.         }
  13.     }
  14.  
  15. }

 
 

3.TankTimeProxy.java

  1. public
    class TankTimeProxy implements Movable {
  2.  
  3.     Movable m;
  4.  
  5.     public TankTimeProxy(Movable m) {
  6.         this.m = m;
  7.     }
  8.  
  9.     @Override
  10.     public
    void move() {
  11.         System.out.println("Time Proxy start...........");
  12.         long start = System.currentTimeMillis();
  13.         m.move();
  14.         long end = System.currentTimeMillis();
  15.         System.out.println("花费时间:"+(end - start));
  16.         System.out.println("Time Proxy end...........");
  17.     }
  18.  
  19. }

 

4.TankLogProxy.java

  1. public
    class TankLogProxy implements Movable {
  2.     Movable m;
  3.     public TankLogProxy(Movable m) {
  4.         this.m = m;
  5.     }
  6.     @Override
  7.     public
    void move() {
  8.         System.out.println("Log Proxy start...........");
  9.         m.move();
  10.         System.out.println("Log Proxy end...........");
  11.     }
  12. }

 
 

5.Tank2Time.java

  1. public
    class Tank2Time extends Tank {
  2.  
  3.     public
    void move(){
  4.         System.out.println("Tank2 time start...........");
  5.         long start = System.currentTimeMillis();
  6.         super.move();
  7.         long end = System.currentTimeMillis();
  8.         System.out.println("花费时间:"+(end - start));
  9.         System.out.println("Tank2 time end...........");
  10.     }
  11. }

 
 

6.Tank3Log.java

  1. public
    class Tank3Log extends Tank2Time {
  2.  
  3.     public
    void move(){
  4.         System.out.println("Tank3Log start...........");
  5.         super.move();
  6.         System.out.println("Tank3Log end...........");
  7.     }
  8. }

 
 

7.Client.java

  1. public
    class Client {
  2.  
  3.     @Test
  4.     public
    void testProxy(){
  5.         Tank t = new Tank();
  6.         Movable m;
  7.         //一、聚合的方式(较灵活,因为实现了接口)
  8.         //1.1聚合方式的代理,先日志代理,后时间代理
  9.         TankTimeProxy ttp1 = new TankTimeProxy(t);
  10.         TankLogProxy tlp1 = new TankLogProxy(ttp1);
  11.         m = tlp1;
  12.         m.move();
  13.         System.out.println("\n==============================分隔线==========================\n");
  14.         //1.2聚合方式的代理,先时间代理,后日志代理(可以灵活切换顺序)
  15.         TankLogProxy tlp2 = new TankLogProxy(t);
  16.         TankTimeProxy ttp2 = new TankTimeProxy(tlp2);
  17.         m = ttp2;
  18.         m.move();
  19.         System.out.println("\n==============================分隔线==========================\n");
  20.         //二、继承的方式
  21.         //2.1代理时间
  22.         Tank2Time t2 = new Tank2Time();
  23.         t2.move();
  24.         System.out.println("\n==============================分隔线==========================\n");
  25.         //2.2先代理日志,后时间,不能灵活切换
  26.         Tank3Log t3 = new Tank3Log();
  27.         t3.move();
  28.     }
  29. }

 
 

三、运行结果

 
 

四、小结

凡是要求灵活多变的功能,多数用接口多态实现

 

 

三:问题引出

每实现一个需求都需要写一个代理类,比如:为了实现在方法前后加日志TankLogProxy、为了实现记录方法运行时间TankTimeProxy,随着系统的复杂,如果还需要实现权限、事务管理,用这种设计方法,代理类会越来越多。有没有一种方式,能够让我们不写这些代理类? 动态代理,动态的去代理,代理类是动态生成的,不需要我们编写,这样就可以解决这个代理类很多的问题,这样会极大地减少了我们的工作。

 

 

 

 

 

代理模式-动态代理 调用Proxy.newProxyInstance()

http://www.cnblogs.com/shamgod/p/4592014.html

一、概述

1.目标:不自己写代理类,利用Proxy.newProxyInstance()动态生成

2.用到的知识点:

(1)//编译源码,生成class,注意编译环境要换成jdk1.6才有compiler,单纯的jre没有compiler,会空指针错误

JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
(2)//文件管事器
StandardJavaFileManager fileMgr = jc.getStandardFileManager(null, null, null);
(3)//编译单元
Iterable units = fileMgr.getJavaFileObjects(file);
(4)//编译任务
CompilationTask t = jc.getTask(null, fileMgr, null, null, null, units);

(5)//编译
t.call();

(6)//把类load到内存里

URL[] urls = new URL[] {new URL("file:/"+System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.class")};
URLClassLoader uc = new URLClassLoader(urls);
Class c = uc.loadClass("proxy.TankTimeProxy");

(7)//生成实例

//return c.newInstance(); //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错
Constructor ctr = c.getConstructor(Movable.class);
return ctr.newInstance(new Tank());

 
 

二、代码

1.Movable.java

2.Tank.java

3.Proxy.java

4.Client.java

 1.Moveable.java

  1. package com.weiqinshian.proxy;
  2. public
    interface Moveable
  3. {
  4.    public
    void move();
  5. }

 

2.Tank.java

  1. package com.weiqinshian.proxy;
  2. import java.util.Random;
  3. public
    class Tank implements Moveable
  4. {
  5.    @Override
  6.    public
    void move()
  7.    {
  8.       System.out.println("tank move........");
  9.       try
  10.       {
  11.          Thread.sleep(new Random().nextInt(10000));
  12.       } catch (InterruptedException e)
  13.       {
  14.          e.printStackTrace();
  15.       }
  16.    }
  17. }

 

3.Proxy.java

  1. package com.weiqinshian.proxy;
  2. import java.io.File;
  3. import java.io.FileWriter;
  4. import java.lang.reflect.Constructor;
  5. import java.net.URL;
  6. import java.net.URLClassLoader;
  7. import javax.tools.JavaCompiler;
  8. import javax.tools.StandardJavaFileManager;
  9. import javax.tools.ToolProvider;
  10. import javax.tools.JavaCompiler.CompilationTask;
  11. public
    class Proxy
  12. {
  13.    public
    static Object newProxyInstance() throws Exception
  14.    {
  15.       String rt = "\n\r";
  16.       // 动态代理文件的源码
  17.       String str = "package com.weiqinshian.proxy;" + rt +
  18.       "public class TankTimeProxy implements Moveable {" + rt +
  19.       "private Moveable m;" + rt +
  20.       "public TankTimeProxy(Moveable m) {" + rt + "this.m = m;" + rt + "}" + rt +
  21.       "@Override" + rt + "public void move() {" + rt + "System.out.println(\"Time Proxy start...........\");" + rt + "long start = System.currentTimeMillis();" + rt + "m.move();" + rt
  22.             + "long end = System.currentTimeMillis();" + rt + "System.out.println(\"花费时间:\"+(end - start));" + rt + "System.out.println(\"Time Proxy end...........\");" + rt + "}" + rt +
  23.             "}";
  24.       // 把源码写到java文件里
  25.       File file = new File("d:/src/com/weiqinshian/proxy/TankTimeProxy.java");
  26.       FileWriter fw = new FileWriter(file);
  27.       fw.write(str);
  28.       fw.flush();
  29.       fw.close();
  30.       // 编译源码,生成class,注意编译环境要换成jdk才有compiler,单纯的jre没有compiler,会空指针错误
  31.       JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
  32.       // 文件管事器
  33.       StandardJavaFileManager fileMgr = jc.getStandardFileManager(null, null, null);
  34.       // 编译单元
  35.       Iterable units = fileMgr.getJavaFileObjects(file);
  36.       // 编译任务
  37.       CompilationTask t = jc.getTask(null, fileMgr, null, null, null, units);
  38.       // 编译
  39.       t.call();
  40.       fileMgr.close();
  41.       // 把类load到内存里src\com\weiqinshian\proxy
  42.       URL[] urls = new URL[]
  43.       { new URL("file:/" + "d:/src/") };
  44.       System.out.println("file:/" + System.getProperty("user.dir") + "/src/com/weiqinshian/proxy/TankTimeProxy.class");
  45.       URLClassLoader uc = new URLClassLoader(urls);
  46.       Class c = uc.loadClass("com.weiqinshian.proxy.TankTimeProxy");
  47.       // 生成实例
  48.       // return c.newInstance();
  49.       // //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错
  50.       Constructor ctr = c.getConstructor(Moveable.class);
  51.       return ctr.newInstance(new Tank());
  52.    }
  53. }

 
 

4.Client.java

  1.  package com.weiqinshian.proxy;
  2. public
    class Client
  3. {
  4.    public
    static
    void main(String[] args) throws Exception
  5.    {
  6.       Moveable m = (Moveable) Proxy.newProxyInstance();
  7.       m.move();// 感觉没有生成任何代理类
  8.    }
  9. }

三、运行结果

 
 

 

三、问题引出

现在动态代理,动态生成的代理类是写死了的,是用字符串写死在类里面的,而且,只能动态生成实现了 Moveable接口的代理,如果要实现任意接口的代理应该怎么办? 那就不将动态生成代理类的字符串写死,动态拼接生成代理类。

代理模式--动态代理 修改成可以代理任意接口

 

一、概述

1.目标:把Proxy修改成可以代理任意接口及其任意方法,只要传接口名给newProxyInstance,就能动态生成实现了该接口的代理类。

2.思路:

(1)代理任意接口:把接口类型作为参数传给Proxy的newProxyInstance(Class interfze)

(2)代理任意方法:用interfze.getMethods()取出所有方法,拼接实现方法的字符串

 
 

二、代码

1.Movable.java

2.Tank.java

3.Proxy.java

4.Client.java

 
 

1.Movable.java

  1. package com.weiqinshian.proxy;
  2. public
    interface Moveable
  3. {
  4.    public
    void move();
  5.    public
    void stop();
  6. }

 
 

2.Tank.java

  1. package com.weiqinshian.proxy;
  2. import java.util.Random;
  3. public
    class Tank implements Moveable
  4. {
  5.    @Override
  6.    public
    void move()
  7.    {
  8.       System.out.println("tank move........");
  9.       try
  10.       {
  11.          Thread.sleep(new Random().nextInt(10000));
  12.       } catch (InterruptedException e)
  13.       {
  14.          e.printStackTrace();
  15.       }
  16.    }
  17.    public
    void stop()
  18.    {
  19.       System.out.println("Tank stopping.......");
  20.    }
  21. }

 

3.Proxy.java

  1. package com.weiqinshian.proxy;
  2. import java.io.File;
  3. import java.io.FileWriter;
  4. import java.lang.reflect.Constructor;
  5. import java.lang.reflect.Method;
  6. import java.net.URL;
  7. import java.net.URLClassLoader;
  8. import javax.tools.JavaCompiler;
  9. import javax.tools.StandardJavaFileManager;
  10. import javax.tools.ToolProvider;
  11. import javax.tools.JavaCompiler.CompilationTask;
  12.  
  13. public
    class Proxy
  14. {
  15.    public
    static Object newProxyInstance(Class interfze) throws Exception
  16.    {
  17.       String rt = "\n\r";
  18.       // 拼接"实现接口方法"的字符串
  19.       String methodStr = "";
  20.       for (Method m : interfze.getMethods())
  21.       {
  22.          // 取出方法的修饰符和返回值类型
  23.          String[] parts = m.toString().replace("abstract ", "").split("\\.");
  24.          String[] parts2 = parts[0].split("
    ");
  25.          methodStr += "@Override" + rt + parts2[0] + "
    " + parts2[1] + "
    " + m.getName() + "() {" + rt + "System.out.println(\"Time Proxy start...........\");" + rt
  26.                + "long start = System.currentTimeMillis();" + rt + "m." + m.getName() + "();" + rt + "long end = System.currentTimeMillis();" + rt
  27.                + "System.out.println(\"花费时间:\"+(end - start));" + rt + "System.out.println(\"Time Proxy end...........\");" + rt + "}";
  28.       }
  29.       // 动态代理文件的源码
  30.       String str = "package com.weiqinshian.proxy; " + rt +
  31.       "public class TankTimeProxy implements " + interfze.getName() + " {" + rt +
  32.       "private " + interfze.getName() + " m;" + rt +
  33.       "public TankTimeProxy(" + interfze.getName() + " m) {" + rt + "this.m = m;" + rt + "}" + rt +
  34.       methodStr + rt +
  35.       "}";
  36.       // 把源码写到java文件里
  37.       File file = new File("d:/src/com/weiqinshian/proxy/TankTimeProxy.java");
  38.       FileWriter fw = new FileWriter(file);
  39.       fw.write(str);
  40.       fw.flush();
  41.       fw.close();
  42.       // 编译源码,生成class,注意编译环境要换成jdk才有compiler,单纯的jre没有compiler,会空指针错误
  43.       JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
  44.       // 文件管事器
  45.       StandardJavaFileManager fileMgr = jc.getStandardFileManager(null, null, null);
  46.       // 编译单元
  47.       Iterable units = fileMgr.getJavaFileObjects(file);
  48.       // 编译任务
  49.       CompilationTask t = jc.getTask(null, fileMgr, null, null, null, units);
  50.       // 编译
  51.       t.call();
  52.       fileMgr.close();
  53.       // 把类load到内存里src\com\weiqinshian\proxy
  54.       URL[] urls = new URL[]
  55.       { new URL("file:/" + "d:/src/") };
  56.       System.out.println("file:/" + System.getProperty("user.dir") + "/src/com/weiqinshian/proxy/TankTimeProxy.class");
  57.       URLClassLoader uc = new URLClassLoader(urls);
  58.       Class c = uc.loadClass("com.weiqinshian.proxy.TankTimeProxy");
  59.       // 生成实例
  60.       // return c.newInstance();
  61.       // //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错
  62.       Constructor ctr = c.getConstructor(interfze);
  63.       return ctr.newInstance(new Tank());
  64.    }
  65. }

 
 

4.Client.java

  1. package com.weiqinshian.proxy;
  2.  
  3. public
    class Client
  4. {
  5.    public
    static
    void main(String[] args) throws Exception
  6.    {
  7.       Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class);// 方法参数可以传任意接口类型
  8.       m.move();
  9.       m.stop();
  10.    }
  11. }

 

三、运行结果

TankTimeProxy 动态生成的类

  1. package com.weiqinshian.proxy;
  2. public
    class TankTimeProxy implements com.weiqinshian.proxy.Moveable {
  3.     private com.weiqinshian.proxy.Moveable m;
  4.     public TankTimeProxy(com.weiqinshian.proxy.Moveable m) {
  5.         this.m = m;
  6.     }
  7.     @Override
  8.     public
    void stop() {
  9.         System.out.println("Time Proxy start...........");
  10.         long start = System.currentTimeMillis();
  11.         m.stop();
  12.         long end = System.currentTimeMillis();
  13.         System.out.println("花费时间:" + (end - start));
  14.         System.out.println("Time Proxy end...........");
  15.     }
  16.     @Override
  17.     public
    void move() {
  18.         System.out.println("Time Proxy start...........");
  19.         long start = System.currentTimeMillis();
  20.         m.move();
  21.         long end = System.currentTimeMillis();
  22.         System.out.println("花费时间:" + (end - start));
  23.         System.out.println("Time Proxy end...........");
  24.     }
  25. }

四、问题引出

上面这种方式生成的动态代理,只能生成时间上的代理。我要想生成一个log、权限代理,还是需要再写一个Proxy动态代理类,怎么解决这个问题?我们在可以在生成代理类的同时,调用一个别人指定给我的处理方式。

在代理里面调用方法的时候,方法前面加什么(比如:日志),后面加什么,不写死,由别人动态指定。方法的执行交给别人了执行,而执行的过程,可以由我们自己来定(多态)。

思路:将大问题分解为小问题

第一步:需要一个可以动态指定对某一方法进行处理的东西 (InvocationHandler 接口,方法调用处理器)

第二步:TimeHandler

代理模式-动态代理 修改成可以任意修改代理逻辑

一、概述

1.目标:动态代理的代理逻辑可以任意修改

2.思路:

(1)要把代理逻辑抽离,站在jvm的角度思考,应独立出InvocationHandler接口,并接收被代理的对象及方法作为参数invoke(Object o, Method m),并本身作为参数传给newProxyInstance(Class interfze,InvocationHandler handler) 

(2)InvocationHandler本身聚合被代理类target,以便在target的方法前后增加代理逻辑

3.知识点:

(1)按名字找方法java.lang.reflect.Method md = proxy.Movable.class.getMethod("stop");

(2)按"."拆分字符串:String [] parts = m.toString().replace("abstract ", "").split("\\.");

 
 

二、代码

1.InvocationHandler.java

2.TimeHandler.java

3.Movable.java

4.Tank.java

5.Proxy.java

6.Client.java

 
 

1.InvocationHandler.java

  1. package com.weiqinshian.proxy;
  2. import java.lang.reflect.Method;
  3. public
    interface InvocationHandler
  4. {
  5.    public
    void invoke(Object o, Method m);
  6. }

2.TimeHandler.java

  1. package com.weiqinshian.proxy;
  2. import java.lang.reflect.Method;
  3. public
    class TimeHandler implements InvocationHandler
  4. {
  5.    // 保留被代理的对象
  6.    private Object target;
  7.    public TimeHandler(Object target)
  8.    {
  9.       this.target = target;
  10.    }
  11.    public
    void invoke(Object o, Method m)
  12.    {
  13.       System.out.println("Time Proxy start...........");
  14.       long start = System.currentTimeMillis();
  15.       try
  16.       {
  17.          // 除了静态方法,方法的调用都要先已知对象,所以要把对象o作为参数传进去
  18.          m.invoke(target);
  19.       } catch (Exception e)
  20.       {
  21.          e.printStackTrace();
  22.       }
  23.       long end = System.currentTimeMillis();
  24.       System.out.println("花费时间:" + (end - start));
  25.       System.out.println("Time Proxy end...........");
  26.    }
  27. }

 

3.Moveable.java

  1. package com.weiqinshian.proxy;
  2.  
  3. public
    interface Moveable
  4. {
  5.    public
    void move();
  6.    public
    void stop();
  7. }

 

4.Tank.java

  1. package com.weiqinshian.proxy;
  2.  
  3. import java.util.Random;
  4.  
  5. public
    class Tank implements Moveable
  6. {
  7.  
  8.    @Override
  9.    public
    void move()
  10.    {
  11.       System.out.println("tank move........");
  12.       try
  13.       {
  14.          Thread.sleep(new Random().nextInt(10000));
  15.       } catch (InterruptedException e)
  16.       {
  17.          e.printStackTrace();
  18.       }
  19.  
  20.    }
  21.  
  22.    public
    void stop()
  23.    {
  24.       System.out.println("Tank stopping.......");
  25.  
  26.    }
  27. }

 
 

5.Proxy.java

  1. package com.weiqinshian.proxy;
  2.  
  3. import java.io.File;
  4. import java.io.FileWriter;
  5. import java.lang.reflect.Constructor;
  6. import java.lang.reflect.Method;
  7. import java.net.URL;
  8. import java.net.URLClassLoader;
  9.  
  10. import javax.tools.JavaCompiler;
  11. import javax.tools.StandardJavaFileManager;
  12. import javax.tools.ToolProvider;
  13. import javax.tools.JavaCompiler.CompilationTask;
  14.  
  15. public
    class Proxy
  16. {
  17.  
  18.    public
    static Object newProxyInstance(Class interfze, InvocationHandler handler) throws Exception
  19.    {
  20.       String rt = "\n\r";
  21.       // 拼接"实现接口方法"的字符串
  22.       String methodStr = "";
  23.       for (Method m : interfze.getMethods())
  24.       {
  25.          // 取出方法的修饰符和返回值类型
  26.          String[] parts = m.toString().replace("abstract ", "").split("\\.");
  27.          String[] parts2 = parts[0].split("
    ");
  28.  
  29.          methodStr += "@Override" + rt + parts2[0] + "
    " + parts2[1] + "
    " + m.getName() + "() {" + rt + "try{" + rt + "java.lang.reflect.Method md = " + interfze.getName() + ".class.getMethod(\""
  30.                + m.getName() + "\");" + rt +
  31.                // 传this进去其实没什么用,invoke实际是调用target的方法m.invoke(target)
  32.                "handler.invoke(this, md);" + rt + "}catch(Exception e){" + rt + " e.printStackTrace();" + rt + "}" + rt + "}" + rt;
  33.       }
  34.       // 动态代理文件的源码
  35.       String str = " package com.weiqinshian.proxy; " + rt +
  36.  
  37.       "public class TankTimeProxy implements " + interfze.getName() + " {" + rt +
  38.  
  39.       // 聚合Handler
  40.             "private InvocationHandler handler;" + rt +
  41.  
  42.             "public TankTimeProxy(InvocationHandler handler) {" + rt + "this.handler = handler;" + rt + "}" + rt + methodStr + rt + "}";
  43.  
  44.       // 把源码写到java文件里
  45.       File file = new File("d:/src/com/weiqinshian/proxy/TankTimeProxy.java");
  46.       FileWriter fw = new FileWriter(file);
  47.       fw.write(str);
  48.       fw.flush();
  49.       fw.close();
  50.  
  51.       // 编译源码,生成class,注意编译环境要换成jdk才有compiler,单纯的jre没有compiler,会空指针错误
  52.       JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
  53.  
  54.       // 文件管事器
  55.       StandardJavaFileManager fileMgr = jc.getStandardFileManager(null, null, null);
  56.  
  57.       // 编译单元
  58.       Iterable units = fileMgr.getJavaFileObjects(file);
  59.  
  60.       // 编译任务
  61.       CompilationTask t = jc.getTask(null, fileMgr, null, null, null, units);
  62.  
  63.       // 编译
  64.       t.call();
  65.       fileMgr.close();
  66.  
  67.       // 把类load到内存里src\com\weiqinshian\proxy
  68.       URL[] urls = new URL[]
  69.       { new URL("file:/" + "d:/src/") };
  70.       System.out.println("file:/" + System.getProperty("user.dir") + "/src/com/weiqinshian/proxy/TankTimeProxy.class");
  71.       URLClassLoader uc = new URLClassLoader(urls);
  72.       Class c = uc.loadClass("com.weiqinshian.proxy.TankTimeProxy");
  73.  
  74.       // 生成实例
  75.       // return c.newInstance();
  76.       // //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错
  77.       // Constructor ctr = c.getConstructor(interfze);
  78.       Constructor ctr = c.getConstructor(InvocationHandler.class);
  79.       return ctr.newInstance(handler);
  80.  
  81.    }
  82. }

 6.Client.java

作为客户来讲,调用这个方法的时候传了接口,我就知道方法返回的对象是实现了那个接口的,所以,强制转换为接口,这个肯定是没有什么问题的,往里面传new timeHandler,我自己要做什么样的代理的实现是由我自己来决定的

  1. package com.weiqinshian.proxy;
  2. public
    class Client
  3. {
  4.    public
    static
    void main(String[] args) throws Exception
  5.    {
  6.       Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class, new TimeHandler(new Tank()));//
  7.       m.move();
  8.       m.stop();
  9.    }
  10. }

 
 

三、运行结果

 

四、动态生成代码

  1. package com.weiqinshian.proxy;
  2. import java.lang.reflect.InvocationHandler;
  3. public
    class TankTimeProxy implements com.weiqinshian.proxy.Moveable {
  4.     private InvocationHandler handler;
  5.     public TankTimeProxy(InvocationHandler handler) {
  6.         this.handler = handler;
  7.     }
  8.     @Override
  9.     public
    void stop() {
  10.         try {
  11.             java.lang.reflect.Method md = com.weiqinshian.proxy.Moveable.class.getMethod("stop");
  12.             handler.invoke(this, md);
  13.         } catch (Exception e) {
  14.             e.printStackTrace();
  15.         }
  16.     }
  17.     @Override
  18.     public
    void move() {
  19.         try {
  20.             java.lang.reflect.Method md = com.weiqinshian.proxy.Moveable.class.getMethod("move");
  21.             handler.invoke(this, md);
  22.         } catch (Exception e) {
  23.             e.printStackTrace();
  24.         }
  25.     }
  26. }

CGLIB 和ASM 可以直接修改二进制码实现动态代理

 

CGLIB(Code Generation Library)是一个开源项目!

是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。

 

ASM 是一个 Java 字节码操控框架。它能够以二进制形式修改已有类或者动态生成类。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

 

最新文章

  1. 【LeetCode】Roman to Integer & Integer to Roman
  2. mongodb学习03 操作详解
  3. CF 628C --- Bear and String Distance --- 简单贪心
  4. ziparchiver添加后编译出错
  5. JADE平台入门
  6. 导入表 IMPORT_DESCRIPTOR
  7. tomcat运行war包报错,找不到context-root文件
  8. 基于.netstandard的权限控制组件
  9. LeetCode 530. Minimum Absolute Difference in BST (二叉搜索树中最小绝对差)
  10. css元素选择器 first-child nth-child
  11. C语言作业(三)
  12. 搭建SpringBoot+dubbo+zookeeper+maven框架(二)
  13. 如何写好.babelrc?Babel的presets和plugins配置解析
  14. AtomicReference实现单例模式
  15. linux nat style
  16. Linux6.5 安装Python3.X(转载)
  17. 牛客网暑期ACM多校训练营(第三场)DEncrypted String Matching fft
  18. airtest IDE问题汇总
  19. AJAX XML 实例
  20. 二进制搭建kubernetes多master集群【三、配置k8s master及高可用】

热门文章

  1. Python操作rabbitmq 实践笔记
  2. iOS 多个异步网络请求全部返回后再执行具体逻辑的方法
  3. Bravebeart
  4. VisualStudio控制台输出窗口一闪而过
  5. 解决java.lang.InstantiationError: sun.net.ftp.FtpClient
  6. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室 实战系列
  7. iOS之自定义控件
  8. js根据不同浏览器(分辨率)调用不同css
  9. sql server 日期
  10. 利用ipython实现多线程