zoukankan      html  css  js  c++  java
  • Java-马士兵动态代理模式

    Java-马士兵动态代理模式

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

    java动态代理有什么作用

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

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

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

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

     

    一、概述

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

    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(" ==============================分隔线========================== ");
    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(" ==============================分隔线========================== ");
    20.         //二、继承的方式
    21.         //2.1代理时间
    22.         Tank2Time t2 = new Tank2Time();
    23.         t2.move();
    24.         System.out.println(" ==============================分隔线========================== ");
    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 = " ";
    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到内存里srccomweiqinshianproxy
    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)代理任意接口:把接口类型作为参数传给ProxynewProxyInstance(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 = " ";
    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到内存里srccomweiqinshianproxy
    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 = " ";
    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到内存里srccomweiqinshianproxy
    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 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

     

  • 相关阅读:
    黑鲨2无限重启 把竞技按钮调到最上
    绿联 电池
    阿里云
    Centos 8 搭建时钟服务器
    CentOS8系统时间同步解决方法
    解决问题的人干活快的人
    【海通国际】Joe Lowry(Mr. Lithium)谈全球电池原材料供应危机
    Linux 实验楼
    用 set follow-fork-mode child即可。这是一个 gdb 命令,其目的是告诉 gdb 在目标应用调用fork之后接着调试子进程而不是父进程,因为在 Linux 中fork系统调用成功会返回两次,一次在父进程,一次在子进程
    【随笔】阿里云修改DNS
  • 原文地址:https://www.cnblogs.com/weiqinshian/p/5997983.html
Copyright © 2011-2022 走看看