代理模式及JDK动态代理(InvocationHandler)的简单实现与分析

在慕课网上学习了讲解代理模式的一个课程--《模式的秘密--代理模式》,感叹于David老师屌炸天的PPT,同时,老师一步一步模仿JDK源码去写code,教我们去简单实现JDK中的动态代理,讲的清晰透彻。在此我做下笔记,课程原地址:http://www.imooc.com/learn/214

 

一、概述

代理模式定义:为其他对象提供一种代理,以控制对这个对象的访问。代理对象起到中介作用,可以去掉功能服务或增加额外的服务。

常见的代理模式:

(1)远程代理:给一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又称为大使(Ambassador)。

(2)虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建。e.g. 刷网页,先显示预先准备好的背景图,等真正的图片加载完成后再显示。

(3)保护代理:控制用户的访问权限

(4)智能引用代理:提供对目标对象额外的服务

代理的实现方式:静态代理、动态代理

 

二、静态代理

代理和被代理对象在代理之前是确定的,他们都实现相同的接口或者继承相同的抽象类。类图如下:

 

举例如下:

 

  1.  
    package com.test.proxytest;
  2.  
     
  3.  
    //抽象对象角色
  4.  
    interface IMacBook {
  5.  
    void buyIt();
  6.  
    }
  7.  
    //目标对象角色
  8.  
    class HangKangMacBook implements IMacBook {
  9.  
    @Override
  10.  
    public void buyIt() {
  11.  
    System.out.println("This computer is from HangKang!");
  12.  
    }
  13.  
    }
  14.  
    //代理对象角色
  15.  
    class ProxyMacBook implements IMacBook {
  16.  
    @Override
  17.  
    public void buyIt() {
  18.  
    HangKangMacBook mac = new HangKangMacBook();
  19.  
    mac.buyIt();
  20.  
    }
  21.  
    }
  22.  
    //客户端
  23.  
    public class Main {
  24.  
    public static void main(String[] args) {
  25.  
    IMacBook macBook = new ProxyMacBook();
  26.  
    macBook.buyIt();
  27.  
    }
  28.  
    }

 

 

三、JDK动态代理

 

Java动态代理位于java.lang.reflect包下,一般主要涉及到以下两个类:

(1)Interface InvocationHandler

该接口中仅定义了一个方法:public Object invoke(Object obj, Method method, Object[] args),在使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。

(2)Proxy

该类即为动态代理类,static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h),返回代理类的一个实例,返回后的代理类可以当作被代理类使用。

JDK动态代理的一般实现步骤如下:

(1)创建一个实现InvocationHandler接口的类,它必须实现invoke方法

(2)创建被代理的类以及接口

(3)调用Proxy的静态方法newProxyInstance,创建一个代理类

(4)通过代理调用方法

举例如下:

 

  1.  
    public interface Moveable {
  2.  
    void move();
  3.  
    }
  1.  
    public class Car implements Moveable {
  2.  
     
  3.  
    @Override
  4.  
    public void move() {
  5.  
    //实现开车
  6.  
    try {
  7.  
    Thread.sleep(new Random().nextInt(1000));
  8.  
    System.out.println("汽车行驶中....");
  9.  
    } catch (InterruptedException e) {
  10.  
    e.printStackTrace();
  11.  
    }
  12.  
    }
  13.  
     
  14.  
    }
  1.  
    public class TimeHandler implements InvocationHandler {
  2.  
     
  3.  
    public TimeHandler(Object target) {
  4.  
    super();
  5.  
    this.target = target;
  6.  
    }
  7.  
     
  8.  
    private Object target;
  9.  
     
  10.  
    /*
  11.  
    * 参数:
  12.  
    * proxy 被代理对象
  13.  
    * method 被代理对象的方法
  14.  
    * args 方法的参数
  15.  
    *
  16.  
    * 返回值:
  17.  
    * Object 方法的返回值
  18.  
    * */
  19.  
    @Override
  20.  
    public Object invoke(Object proxy, Method method, Object[] args)
  21.  
    throws Throwable {
  22.  
    long starttime = System.currentTimeMillis();
  23.  
    System.out.println("汽车开始行驶....");
  24.  
    method.invoke(target);
  25.  
    long endtime = System.currentTimeMillis();
  26.  
    System.out.println("汽车结束行驶.... 汽车行驶时间:"
  27.  
    + (endtime - starttime) + "毫秒!");
  28.  
    return null;
  29.  
    }
  30.  
     
  31.  
    }
  1.  
    public class Test {
  2.  
     
  3.  
    /**
  4.  
    * JDK动态代理测试类
  5.  
    */
  6.  
    public static void main(String[] args) {
  7.  
    Car car = new Car();
  8.  
    InvocationHandler h = new TimeHandler(car);
  9.  
    Class<?> cls = car.getClass();
  10.  
    /**
  11.  
    * loader 类加载器
  12.  
    * interfaces 实现接口
  13.  
    * h InvocationHandler
  14.  
    */
  15.  
    Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),
  16.  
    cls.getInterfaces(), h);
  17.  
    m.move();
  18.  
    }
  19.  
     
  20.  
    }

运行结果如下:

 

四、JDK动态代理的简易实现

动态代理的实现思路

实现功能:通过Proxy的newProxyInstance返回代理对象

(1)声明一段源码(动态产生代理)

(2)编译源码(JDK Compiler API),产生新的类(代理类)

(3)将这个类load到内存当中,产生一个新的对象(代理对象)

(4)return代理对象

 

  1.  
    package com.mhb.proxy;
  2.  
     
  3.  
    public interface Moveable {
  4.  
    void move();
  5.  
    }
  1.  
    package com.mhb.proxy;
  2.  
     
  3.  
    import java.util.Random;
  4.  
     
  5.  
    public class Car implements Moveable {
  6.  
     
  7.  
    @Override
  8.  
    public void move() {
  9.  
    //实现开车
  10.  
    try {
  11.  
    Thread.sleep(new Random().nextInt(1000));
  12.  
    System.out.println("汽车行驶中....");
  13.  
    } catch (InterruptedException e) {
  14.  
    e.printStackTrace();
  15.  
    }
  16.  
    }
  17.  
     
  18.  
    }
  1.  
    package com.mhb.proxy;
  2.  
     
  3.  
    import org.apache.commons.io.FileUtils;
  4.  
     
  5.  
    import javax.tools.JavaCompiler;
  6.  
    import javax.tools.JavaCompiler.CompilationTask;
  7.  
    import javax.tools.StandardJavaFileManager;
  8.  
    import javax.tools.ToolProvider;
  9.  
    import java.io.File;
  10.  
    import java.lang.reflect.Constructor;
  11.  
    import java.lang.reflect.Method;
  12.  
     
  13.  
    public class Proxy {
  14.  
     
  15.  
    @SuppressWarnings("unchecked")
  16.  
    public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{
  17.  
    String rt = "\n";
  18.  
    String rx = " ";
  19.  
    String methodStr = "";
  20.  
    for(Method m : infce.getMethods()){
  21.  
    methodStr +=
  22.  
    "@Override" + rt + rx +
  23.  
    "public void " + m.getName() + "() {" + rt + rx +
  24.  
    " try{" + rt + rx +
  25.  
    " Method md = " + infce.getName() + ".class.getMethod(\""+ m.getName() + "\");" + rt + rx +
  26.  
    " h.invoke(this,md);" + rt + rx +
  27.  
    " } catch (Exception e) { " + rt + rx +
  28.  
    " e.printStackTrace();" + rt + rx +
  29.  
    " }" + rt + rx +
  30.  
    "}" ;
  31.  
    }
  32.  
     
  33.  
    String str =
  34.  
    "package com.mhb.proxy;" + rt +
  35.  
    "import java.lang.reflect.Method;" + rt +
  36.  
    "import com.mhb.proxy.InvocationHandler;" + rt+
  37.  
    "public class $Proxy0 implements " + infce.getName() + " {" + rt +
  38.  
    " public $Proxy0(InvocationHandler h) {" + rt +
  39.  
    " this.h = h;" + rt +
  40.  
    " }" + rt +
  41.  
    " private InvocationHandler h;" + rt+
  42.  
    " " + methodStr + rt +
  43.  
    "}" ;
  44.  
    //产生代理类的java文件
  45.  
    String filename = System.getProperty("user.dir") +"/bin/com/mhb/proxy/$Proxy0.java";
  46.  
    File file = new File(filename);
  47.  
    FileUtils.writeStringToFile(file, str);
  48.  
     
  49.  
    //编译
  50.  
    //拿到编译器
  51.  
    JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
  52.  
    //文件管理者
  53.  
    StandardJavaFileManager fileMgr =
  54.  
    complier.getStandardFileManager(null, null, null);
  55.  
    //获取文件
  56.  
    Iterable units = fileMgr.getJavaFileObjects(filename);
  57.  
    //编译任务
  58.  
    CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);
  59.  
    //进行编译
  60.  
    t.call();
  61.  
    fileMgr.close();
  62.  
     
  63.  
    //load到内存
  64.  
    ClassLoader cl = ClassLoader.getSystemClassLoader();
  65.  
    Class c = cl.loadClass("com.mhb.proxy.$Proxy0");
  66.  
     
  67.  
    Constructor ctr = c.getConstructor(InvocationHandler.class);
  68.  
    return ctr.newInstance(h);
  69.  
    }
  70.  
    }
  1.  
    package com.mhb.proxy;
  2.  
     
  3.  
    import java.lang.reflect.Method;
  4.  
     
  5.  
    public interface InvocationHandler {
  6.  
     
  7.  
    void invoke(Object o,Method m);
  8.  
    }
  1.  
    package com.mhb.proxy;
  2.  
     
  3.  
    import java.lang.reflect.Method;
  4.  
     
  5.  
    public class TimeHandler implements InvocationHandler {
  6.  
     
  7.  
    private Object target;
  8.  
     
  9.  
    public TimeHandler(Object target) {
  10.  
    super();
  11.  
    this.target = target;
  12.  
    }
  13.  
     
  14.  
    @Override
  15.  
    public void invoke(Object o, Method m) {
  16.  
     
  17.  
    try {
  18.  
    long starttime = System.currentTimeMillis();
  19.  
    System.out.println("汽车开始行驶....");
  20.  
    m.invoke(target);
  21.  
    long endtime = System.currentTimeMillis();
  22.  
    System.out.println("汽车结束行驶.... 汽车行驶时间:"
  23.  
    + (endtime - starttime) + "毫秒!");
  24.  
    } catch (Exception e) {
  25.  
    e.printStackTrace();
  26.  
    }
  27.  
    }
  28.  
    }
  1.  
    package com.mhb.proxy;
  2.  
     
  3.  
    public class Client {
  4.  
     
  5.  
    /**
  6.  
    * 测试类
  7.  
    * @throws Exception
  8.  
    */
  9.  
    public static void main(String[] args) throws Exception {
  10.  
    Car car = new Car();
  11.  
    InvocationHandler h = new TimeHandler(car);
  12.  
    Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class, h);
  13.  
    m.move();
  14.  
    }
  15.  
    }

IntelliJ IDEA目录结构(bin目录需要设为Resources Root):

生成的$Proxy0.java如下:

 

  1.  
    package com.mhb.proxy;
  2.  
    import java.lang.reflect.Method;
  3.  
    import com.mhb.proxy.InvocationHandler;
  4.  
    public class $Proxy0 implements com.mhb.proxy.Moveable {
  5.  
    public $Proxy0(InvocationHandler h) {
  6.  
    this.h = h;
  7.  
    }
  8.  
    private InvocationHandler h;
  9.  
    @Override
  10.  
    public void move() {
  11.  
    try{
  12.  
    Method md = com.mhb.proxy.Moveable.class.getMethod("move");
  13.  
    h.invoke(this,md);
  14.  
    } catch (Exception e) {
  15.  
    e.printStackTrace();
  16.  
    }
  17.  
    }
  18.  
    }



 

运行结果:

 

汽车开始行驶....
汽车行驶中....
汽车结束行驶....  汽车行驶时间:830毫秒!

posted @ 2018-07-17 16:59  天涯海角路  阅读(321)  评论(0)    收藏  举报