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 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

 

Java-马士兵动态代理模式的更多相关文章

  1. Java设计模式—Proxy动态代理模式

    代理:设计模式 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 图 1. 代 ...

  2. java学习之动态代理模式

    package com.gh.dynaproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Metho ...

  3. JAVA动态代理模式(从现实生活角度理解代码原理)

    所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联. java动态代理主要是使用java.lang.reflect包中的两个 ...

  4. 黑马程序员:Java基础总结----静态代理模式&动态代理

    黑马程序员:Java基础总结 静态代理模式&动态代理   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 静态代理模式 public  class  Ts {   ...

  5. Java静态代理与动态代理模式的实现

    前言:    在现实生活中,考虑以下的场景:小王打算要去租房,他相中了一个房子,准备去找房东洽谈相关事宜.但是房东他很忙,平时上班没时间,总找不到时间去找他,他也没办法.后来,房东想了一个办法,他找到 ...

  6. java jdk动态代理模式举例浅析

    代理模式概述 代理模式是为了提供额外或不同的操作,而插入的用来替代”实际”对象的对象,这些操作涉及到与”实际”对象的通信,因此代理通常充当中间人角色. java中常用的动态代理模式为jdk动态代理和c ...

  7. Java的三种代理模式(Spring动态代理对象)

    Java的三种代理模式 1.代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩 ...

  8. Java 代理模式(二) Java中的动态代理

    动态代理类 Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类: 1.Interface InvocationHandler 该接口中仅定义了一个方法: Objec ...

  9. 关于java动态代理模式

    1. 动态代理 动态代理就是通过代理类是代理类与相关接口不直接发生联系,而在运行期(Runtime)实现动态关联. 动态代理主要用到java.lang.reflect包中的两个类,Invocation ...

随机推荐

  1. Qt: 时钟Demo

    其实是一个很简单的Demo,可以编译了拿NSIS打包.最近在做富文本编辑器和补C++不记得的东西吧,项目遥遥无期. //clock.pro #----------------------------- ...

  2. vim 用法

    据说,会使用vim之后,你就不想用其他文本编辑器了...反正我是还没有达到那水平 = = 好啦~不扯蛋,进入正题!(以后这个vim 会不断补充资料的 > <) 简单介绍下~ 一.安装vim ...

  3. 题目:解决.NET项目中的平台选项,由x86设置为AnyCPU

    问题:开发出的.NET程序在windows7 X64平台无法使用,打开提示异常”stopping work….” 1.打开解决方案中的配置管理器,发现有部分程序集的平台是x86,想改变平台选项,发现无 ...

  4. [perl]字符串转拼音首字母(支持多音字)

    实现的思路是,查表找到该字的所有读音,然后取首字母. 代码: while (<DATA>) { chomp; })(.*)$/; $all =~ s/^\s+//; ### 只保留无音标号 ...

  5. ZZULI 1876: 蛤玮的项链 Hash + 二分

    Time Limit: 6 Sec  Memory Limit: 128 MBSubmit: 153  Solved: 11 SubmitStatusWeb Board Description 蛤玮向 ...

  6. oracle 监听启动、停止、查看命令

    1.su oracle 然后启动监听器 1.lsnrctl start  会看到启动成功的界面; 1.lsnrctl stop  停止监听器命令. 1.lsnrctl status  查看监听器命令. ...

  7. Linux 任务控制

    Linux/Unix 提供了不同与 windows 的多任务处理,也提供一套用来切换前后台任务的命令 bg fg & Ctrl+z nohup sitsid Ctrl-Z 挂起程序 user@ ...

  8. hibernate的@EmbeddedId嵌入式主键详解

    一.前言 在我们的日常开发中,有时候会用到数据库进行设计的时候,采用了复合主键来来保证唯一性,下面介绍一下采用hibernate的@EmbeddedId嵌入式主键. 二.说明 设计一个学生类,包含了三 ...

  9. tornado学习笔记14 HTTP1ServerConnection分析

            代表HTTP/1.x 类型的服务器连接,负责处理HTTP/1.x类型的请求. 14.1 构造函数 def __init__(self, stream, params=None, con ...

  10. APP性能测试之卡顿比(FPS)

    fps概念: FPS是图像领域中的定义,是指画面每秒传输帧数,通俗来讲就是指动画或视频的画面数.FPS是测量用于保存.显示动态视频的信息数量.每秒钟帧数愈多,所显示的动作就会愈流畅. 卡顿人体感觉标准 ...