代理三要素

​一个典型的代理模式通常有三个角色,这里称之为代理三要素

  1. 共同的接口
  2. 真实对象
  3. 代理对象
  4. 在代理模式中,其实就是为了让代理对象完成真实对象的过程,同时可以在不侵入真实对象的基础上,对真实对象处理的业务过程进行扩展或者扩充

Java 静态代理

​静态代理其实是通过封装第二方代码进行的业务逻辑嵌套处理的方式,可以创建一个代理类实现和目标方法相同的方法,通过让代理类持有真实对象,然后在原代码中调用代理类方法,来达到添加我们需要业务逻辑的目的。

/** * @program: blogDemo * @description: 共同接口 * @author: Henry.Wang * @create: 2019-03-11 22:51 **/public interface Action { void doSomeString();}/** * @program: blogDemo * @description: 代理对象 * @author: Henry.Wang * @create: 2019-03-11 22:54 **/public class ProxyObject implements Action { private Action realObject; //聚合真实对象 public ProxyObject(Action realObject) { this.realObject = realObject; } @Override public void doSomeString() { System.out.println("代理对象执行业务方法...... 调用真实对象的业务方法"); System.out.println("在真实对象处理之前,进行打印"); realObject.doSomeString(); System.out.println("在真实对象处理之后,进行打印"); }}/** * @program: blogDemo * @description: 真实对象 * @author: Henry.Wang * @create: 2019-03-11 22:52 **/public class RealObject implements Action{ @Override public void doSomeString() { System.out.println("真实对象处理业务......."); }}/** * @program: blogDemo * @description: * @author: Henry.Wang * @create: 2019-03-11 22:59 **/public class main { public static void main(String[] args) { Action realObject = new RealObject(); Action proxyObject = new ProxyObject(realObject); proxyObject.doSomeString(); }}

输出结果:

代理对象执行业务方法...... 调用真实对象的业务方法在真实对象处理之前,进行打印真实对象处理业务.......在真实对象处理之后,进行打印

静态代理的优点和缺点

  • 优点: 代码无侵入性
  • 缺点: 显而易见,当出现多个真实对象,且需要代理的目标方法不同时,只有两种方式
  • 做多个代理对象,分别代理不同的真实对象。
  • 同一个代理对象,分别实现不同的方法,这样会让代理对象是分臃肿,而且当方法签名相同时,需要做过多的逻辑判断。

Java动态代理

​通过使用动态代理,我们可以通过在运行时,动态生成一个持有RealObject、并实现代理接口的Proxy,同时注入我们相同的扩展逻辑。哪怕你要代理的RealObject是不同的对象,甚至代理不同的方法,都可以动过动态代理,来扩展功能。简单理解,动态代理就是我们上面提到的方案一,只不过这些proxy的创建都是自动的并且是在运行期生成的。

​一般我们使用动态代理有两种,JDK和cglib,这两者的区别在于

  • JDK动态代理需要目标对象实现业务接口,代理类需实现InvocationHandler接口
  • JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。
  • 使用cglib代理的对象则无需实现接口,达到代理类无侵入。
  • 二者都是在运行时生成代理的class文件,不过一个是代理类$Proxy0 ,一个是真是的实现类字节码。
  • 动态代理生成的类为 lass com.sun.proxy.$Proxy4,cglib代理生成的类为
  • class com.cglib.xxx实现类EnhancerByCGLIB
  • EnhancerByCGLIB
  • 552188b6。
  • cglib代理无需实现接口,通过生成实现类字节码实现代理,比反射稍快,不存在性能问题,但JDK的动态代理是生成接口的Proxy代理类,通过调用反射的方法调用目标方法,大量的反射会消耗性能。
  • cglib会继承目标对象,需要重写方法,所以目标对象不能为final类。
  • cglib需要实现MethodInterceptor接口。这个接口是为了生成的实现类内置的callback方法提供统一对目标方法进行统一的调用

下面我们分别使用JDK和cglib进行动态代理

JDK动态代理

public interface Action { void doSomeString();}public class DynamicProxyHandler implements InvocationHandler { Object realObject; public DynamicProxyHandler(Object realObject) { this.realObject = realObject; } /** * @description * @param proxy 被代理后的对象 * @param method 将要被执行的方法信息(反射) * @param args 方法参数 * @return java.lang.Object  * @author Henry.Wang * @date 2019/3/11 23:55 */  @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("JDK动态代理对象执行业务方法...... 调用真实对象的业务方法"); System.out.println("JDK动态代理在真实对象处理之前,进行打印"); method.invoke(this.realObject, args); System.out.println("JDK动态代理在真实对象处理之后,进行打印"); return null; }}public class RealObject implements Action { @Override public void doSomeString() { System.out.println("真实对象处理业务......."); }}public class main { public static void main(String[] args) { //定义真实对象 Action action = new RealObject(); //关键步骤 //实例化代理对象,实例化代理对象的过程其实是在运行时动态生成的class文件 //newProxyInstance 需要三个参数 //1. 类加载器 // 2. 被代理对象实现的所有接口数组,这样就可以生成出所有的需要代理的方法 // 3. 代理对象 具体的实现了 InvocationHandler 的对象,在生成$Proxy0 代理类时,通过构造方法注入 // InvocationHandler,用于调用invoke方法,便于反射调用。 // 其实这一步生成的对象与静态代理很想,只是一个用了反射调用,一个是直接调用 Action proxy = (Action) Proxy.newProxyInstance( action.getClass().getClassLoader(), action.getClass().getInterfaces(), new DynamicProxyHandler(action) ); //由此可以看出 Proxy.newProxyInstance生成的 $Proxy0 对象实现了Action,可以直接强转 proxy.doSomeString(); }}

在网上找到了一个proxy生成的代理对象的反编译代码

可以看出来,生成的$Proxy0 继承了proxy并且实现了Action,通过构造方法注入了定义的InvocationHandler实现,底层其实就是通过InvocationHandler调用invoke方法。

package com.sun.proxy;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Action {

private static Method m1;

private static Method m3;

private static Method m2;

private static Method m0;

public $Proxy0(InvocationHandler var1) throws {

super(var1);

}

public final void doSomething() throws {

try {

super.h.invoke(this, m3, (Object[])null);

} catch (RuntimeException | Error var2) {

throw var2;

} catch (Throwable var3) {

throw new UndeclaredThrowableException(var3);

}

}

...

static {

try {

...

m3 = Class.forName("Action").getMethod("doSomething

动态代理和静态代理的区别_动态代理与静态代理相关推荐

  1. 静态ip和动态ip的区别_动态IP和静态IP有哪些区别?

    代理IP的动态IP和静态IP有什么区别?现在还有许多人在问. 简单说动态IP会发生变化,像工号,到不同的公司你会得到不同的工号:而静态IP是不变的,和身份证号一样.这里神鸡IP代理来给大家详细说下. ...

  2. 外观模式和代理模式的联系和区别_设计模式之代理设计模式

    原文首发于微信公众号:jzman-blog,欢迎关注交流! 今天来看一下什么是代理设计模式,顾名思义,代理就是通过中介代替某人做某一件事,对应到我们的程序中就是通过代理对象来控制某个具体对象某个方法的 ...

  3. 动态域名解析服务器离线会引起什么_动态域名解析过程中可能出现的问题及解决方案...

    动态域名在企业中应用非常广泛,金万维动态域名作为一款平稳运行10余年的软件,已是被业界所熟知.该系统由两部分构成,一部分是客户端,运行在用户的主机上:另一部分是服务器,由金万维负责运行. 谓动态域名解 ...

  4. 外观模式和代理模式的联系和区别_设计模式之代理模式

    代理模式 Proxy Intro 代理模式,给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间 ...

  5. dax和m的区别_动态股票K线图----从M语言到DAX表达式

    偶然见别人画的股票K线图,不禁见猎心喜,也来模仿一番.原图是不能动的,一动MACD移动平滑趋势线就没有了.这是微软excel的一个缺陷. 所以我想了一个办法弥补这个缺陷.由于手头没有数据,开始实施网抓 ...

  6. 动态分区分配的“首次适应算法_动态图划分复制算法:Leopard

    数据管理和系统实现课程上要分享的论文:<LEOPARD: Lightweight Edge-Oriented Partitioning and Replication for Dynamic G ...

  7. 动态引入js只能生效一次_动态插入的script脚本执行时间

    在一些场景我们会动态插入script标签加载js. 譬如某个js文件不是很重要,并不是整个页面需要的脚本,可能只是某个功能需要的,这个功能可能是用户点击了某个按钮才触发,入口比较深.且和你页面本身的结 ...

  8. JSP中动态includ与静态includ的区别

    JSP中动态INCLUDE与静态INCLUDE的区别? 动态INCLUDE用jsp:include动作实现 <jsp:include page="included.jsp" ...

  9. 广播动态注册和静态注册的区别

    动态注册和静态注册的区别: 动态注册的广播接收器可以自由的控制注册和取消,有很大的灵活性.但是只能在程序启动之后才能收到广播,此外,不知道你注意到了没,广播接收器的注销是在onDestroy()方法中 ...

  10. 老卫带你学---动态语言和静态语言的区别

    老卫带你学-动态语言和静态语言的区别 1.基本概念 静态语言(强类型语言) 静态语言是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型. 例如:C++.Java ...

最新文章

  1. mysql deadlock found when trying to get lock暴力解决
  2. 数据结构(三)---双向循环链表的实现---java版
  3. 64位Ubuntu 12.04下搭建嵌入式Qt(4.8.6)、QtCreator、qvfb过程全记录
  4. 数学知识在游戏中的运用
  5. python的注释符_Python3 注释和运算符
  6. update关联一个视图的时候特别慢_实现一个简单的Vue.js
  7. java 校验护照_【示例教程】如何使用LEADTOOLS 的JAVA接口从护照中识别和提取数据...
  8. 机器学习集成模型ML ens学习——多层模型集成(一)
  9. 运营商取消不限量套餐 网友:这是变相涨价
  10. 微信测试环境下不能用window.open()
  11. PHP实现限制域名从而保护源代码不被拷贝
  12. mysql编码gbk_更改mysql数据库编码为GBK
  13. 单点登录(SSO)原理
  14. JavaScript--闭包的理解
  15. sublime 3207 激活
  16. 【机器学习】【可解释性】LIME
  17. 面试官:什么是责任链模式?
  18. 微信怎么防封几率大_域名被墙有哪些处理方法?域名被微信封了该怎么解决?
  19. 【容斥原理】【推导】【树状数组】Gym - 101485G - Guessing Camels
  20. 职业教育转型线上,机构要如何通过直播来引流获客?

热门文章

  1. java中的时间戳sssss,Java日期时间API系列35-----Jdk8中java.time包中的新的日期时间API类应用,微秒和纳秒等更精确的时间格式化和解析。...
  2. let var const的区别
  3. 在opensuse tumbleweed 上开发51单片机
  4. zabbix 添加jvm监控
  5. SPOJ VLATTICE Visible Lattice Points 莫比乌斯反演
  6. 黑马程序猿 IO流 ByteArrayInputStream与ByteArrayOutputStream
  7. HDU 5273 Dylans loves sequence【 树状数组 】
  8. MyBatis数据库链接池源码分析
  9. SpringBoot整合Atomikos实现2PC二阶段分布式事务
  10. jdk优先级队列、延迟队列原理