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

一、概述

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

常见的代理模式:

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

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

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

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

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

二、静态代理

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

举例如下:

package com.test.proxytest;//抽象对象角色
interface IMacBook {void buyIt();
}
//目标对象角色
class HangKangMacBook implements IMacBook {@Overridepublic void buyIt() {System.out.println("This computer is from HangKang!");}
}
//代理对象角色
class ProxyMacBook implements IMacBook {@Overridepublic void buyIt() {HangKangMacBook mac = new HangKangMacBook();mac.buyIt();}
}
//客户端
public class Main {public static void main(String[] args) {IMacBook macBook = new ProxyMacBook();macBook.buyIt();}
}

三、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)通过代理调用方法

举例如下:

public interface Moveable {void move();
}
public class Car implements Moveable {@Overridepublic void move() {//实现开车try {Thread.sleep(new Random().nextInt(1000));System.out.println("汽车行驶中....");} catch (InterruptedException e) {e.printStackTrace();}}}
public class TimeHandler implements InvocationHandler {public TimeHandler(Object target) {super();this.target = target;}private Object target;/** 参数:* proxy  被代理对象* method  被代理对象的方法* args 方法的参数* * 返回值:* Object  方法的返回值* */@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {long starttime = System.currentTimeMillis();System.out.println("汽车开始行驶....");method.invoke(target);long endtime = System.currentTimeMillis();System.out.println("汽车结束行驶....  汽车行驶时间:" + (endtime - starttime) + "毫秒!");return null;}}
public class Test {/*** JDK动态代理测试类*/public static void main(String[] args) {Car car = new Car();InvocationHandler h = new TimeHandler(car);Class<?> cls = car.getClass();/*** loader  类加载器* interfaces  实现接口* h InvocationHandler*/Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h);m.move();}}

运行结果如下:

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

动态代理的实现思路

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

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

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

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

(4)return代理对象

package com.mhb.proxy;public interface Moveable {void move();
}
package com.mhb.proxy;import java.util.Random;public class Car implements Moveable {@Overridepublic void move() {//实现开车try {Thread.sleep(new Random().nextInt(1000));System.out.println("汽车行驶中....");} catch (InterruptedException e) {e.printStackTrace();}}}
package com.mhb.proxy;import org.apache.commons.io.FileUtils;import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;public class Proxy {@SuppressWarnings("unchecked")public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{String rt = "\n";String rx = "    ";String methodStr = "";for(Method m : infce.getMethods()){methodStr +="@Override" + rt + rx +"public void " + m.getName() + "() {" + rt + rx +"    try{" + rt + rx +"        Method md = " + infce.getName() + ".class.getMethod(\""+ m.getName() + "\");" + rt + rx +"        h.invoke(this,md);" + rt + rx +"    } catch (Exception e) { " + rt + rx +"        e.printStackTrace();" + rt + rx +"    }" + rt + rx +"}" ;}String str ="package com.mhb.proxy;" + rt +"import java.lang.reflect.Method;" + rt +"import com.mhb.proxy.InvocationHandler;" +  rt+"public class $Proxy0 implements " + infce.getName() + " {" + rt +"    public $Proxy0(InvocationHandler h) {" + rt +"        this.h = h;" + rt +"    }" + rt +"    private InvocationHandler h;" + rt+"    " + methodStr + rt +"}" ;//产生代理类的java文件String filename = System.getProperty("user.dir") +"/bin/com/mhb/proxy/$Proxy0.java";File file = new File(filename);FileUtils.writeStringToFile(file, str);//编译//拿到编译器JavaCompiler complier = ToolProvider.getSystemJavaCompiler();//文件管理者StandardJavaFileManager fileMgr =complier.getStandardFileManager(null, null, null);//获取文件Iterable units = fileMgr.getJavaFileObjects(filename);//编译任务CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);//进行编译t.call();fileMgr.close();//load到内存ClassLoader cl = ClassLoader.getSystemClassLoader();Class c = cl.loadClass("com.mhb.proxy.$Proxy0");Constructor ctr = c.getConstructor(InvocationHandler.class);return ctr.newInstance(h);}
}
package com.mhb.proxy;import java.lang.reflect.Method;public interface InvocationHandler {void invoke(Object o,Method m);
}
package com.mhb.proxy;import java.lang.reflect.Method;public class TimeHandler implements InvocationHandler {private Object target;public TimeHandler(Object target) {super();this.target = target;}@Overridepublic void invoke(Object o, Method m) {try {long starttime = System.currentTimeMillis();System.out.println("汽车开始行驶....");m.invoke(target);long endtime = System.currentTimeMillis();System.out.println("汽车结束行驶....  汽车行驶时间:"+ (endtime - starttime) + "毫秒!");} catch (Exception e) {e.printStackTrace();}}
}
package com.mhb.proxy;public class Client {/*** 测试类* @throws Exception*/public static void main(String[] args) throws Exception {Car car = new Car();InvocationHandler h = new TimeHandler(car);Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class, h);m.move();}
}

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

生成的$Proxy0.java如下:

package com.mhb.proxy;
import java.lang.reflect.Method;
import com.mhb.proxy.InvocationHandler;
public class $Proxy0 implements com.mhb.proxy.Moveable {public $Proxy0(InvocationHandler h) {this.h = h;}private InvocationHandler h;@Overridepublic void move() {try{Method md = com.mhb.proxy.Moveable.class.getMethod("move");h.invoke(this,md);} catch (Exception e) { e.printStackTrace();}}
}

运行结果:

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

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

  1. 代理模式 、JDK动态代理、cglib动态代理

    代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢? 因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思. 再如我 ...

  2. 【设计模式】代理模式之JDK动态代理与CGLIb代理区别

    一.什么是代理? 代理模式是Java中常见的一种模式,英文名字叫走Proxy或者Surrogate,代理的本意是一个人代表另一个人,或者一个机构代表另一个机构,采取行动,因而,代理和现实生活中的中介有 ...

  3. 代理模式之jdk动态代理的实现

    学习动态代理之前需要了解静态代理 并且牢记静态代理的缺点 //首先被代理的类需要实现一个接口 public interface ProxyInterface {public void say(Stri ...

  4. 【Spring6】| GoF之代理模式(JDK动态代理和CGLIB动态代理)

    目录 一:GoF之代理模式 1. 对代理模式的理解 2. 静态代理 3. 动态代理 3.1 JDK动态代理 3.2 CGLIB动态代理 一:GoF之代理模式 1. 对代理模式的理解 生活场景1:牛村的 ...

  5. 代理模式之详谈动态代理模式(Spring的AOP实现)

    java动态代理实现与原理详细分析 1.代理模式 关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 代理 ...

  6. 动态代理,动态代理设计模式 ,JDK动态代理,cglib动态代理

    为什么80%的码农都做不了架构师?>>>    一:在看此篇代码示例前,先看静态代理, 链接地址:http://my.oschina.net/dyyweb/blog/656760   ...

  7. 设计模式(十三) 代理模式和Java动态代理

    Proxy Pattern 1. 什么是代理模式 代理模式: 给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问. Proxy Pattern: Provide a surrogate ...

  8. 代理设计模式(JDK动态代理)什么是代理,静态代理动态代理实现,分析JDK代理实现逻辑,手动实现JDK代理逻辑。

    什么是代理? 从字面意思来看,代理比较好理解,无非就是代为处理的意思.举个例子,现在哪吒有女助理了,所以很多事情都不用我自己去处理了,比如说去银行排队取钱,那么我就可以叫我的女助理去代替我取钱并交给我 ...

  9. 代理模式中的动态代理

    动态代理和静态对比基本思路是一致的,只不过动态代理功能更加强大,随着业务的扩展适应性更强.如果还以找对象为例,使用动态代理相当于是能够适应复杂的业务场景.不仅仅只是父亲给儿子找对象,如果找对象这项业务 ...

最新文章

  1. 解决flex4 分辨率自适应问题
  2. C# 命令行编译器详解
  3. 算法专题 二分法 普及组【2015】四2 C++版
  4. JQuery 总结(6) 锋利的jQuery
  5. android控件常用的属性,android?常用的控件属性
  6. Java 证书pem转KeyStore、jks文件
  7. 实时数据产品实践——美团大交通战场沙盘
  8. Android系列之网络(二)----HTTP请求头与响应头
  9. java新手的第一个小东西,或许小东西都算不上=。 =
  10. Modelsim 教程
  11. xmind 拖拽_XMind 2020
  12. Ruby之父松本行弘的编程人生
  13. Kubernetes实践:使用k8s部署微服务应用
  14. pyodbc 操作SQL Server数据库
  15. el-table 表尾行合并,列合并,统计
  16. WorldPress出现Briefly unavailable for scheduled maintenance. Check back in a minute.的解决方法
  17. JsPlumb获取线数据
  18. Git操作 fatal: bad numeric config value ‘“false”‘ for ‘http.sslverify‘: invalid unit错误
  19. CSUOJ--1633 Landline Telephone Network
  20. python3 selenium web自媒体百家号企鹅号大鱼号acfun站,自动化上传视频以及经验总结分享

热门文章

  1. 在使用backtrader时,遇到 ImportError: cannot import name ‘warnings‘ from ‘matplotlib.dates‘ 报错的解决方法
  2. 毕业设计 - 地铁大数据客流分析系统 设计与实现
  3. 发现内网存活主机的各种姿势
  4. ssh获取公钥,绑定gitlab,ssh-keygen -t rsa命令详解
  5. linux脚本实时监控,linux实时监控命令
  6. 愤怒的小鸟 texture is too large
  7. linux 交叉编译dbus,expat
  8. linux移植expat
  9. 使用ArcGIS Pro发布高程服务(dem)
  10. Linux学习——I2C-MPU6050驱动移植记录