原文链接:https://www.cnblogs.com/takumicx/p/9285230.html

1. 前言

代理模式可以说是生活中处处可见。比如说在携程上定火车票,携程在这里就起到了一个代理的作用,比起我们在官网上或者直接去柜台订票,携程可以为用户提供更多人性化的选择。再比如代购,我自己的mbp就是委托别人从香港买回来的,那么那个代购人就相当于代理,免去了我来回的车费以及办签证的麻烦。直观的理解,代理是这么一个对象,我们可以把工作委托给它,由它帮我们去执行工作同时解决工作相关的各种麻烦,最后把工作成果交给我们。这样一来我们只需要关注问题的核心,并告知代理,而不需要为其他琐碎的细节操心,这正是代理模式最大的好处,让客户端专注于真正的事务处理。具体而言,代理模式分为静态代理和动态代理,它们的设计思想类似,实现却大相径庭。它们的实现方式以及它们的区别是面试时经常会被问到的。下面我们就来详细介绍它们。

2. 代理模式详解

2.1 定义

为另一个对象提供一个替身或占位符以控制对这个对象的访问
定义简单明了。但还是有些没有解释清楚的地方,控制对对象的访问是为了干什么?其实是为了对真实的业务方法作某种形式的增强,比如在业务方法调用前作前置处理,在方法调用后作后置处理,而这些对客户端都是透明的。

2.2 普通代理模式类结构

被代理类和代理类实现同一接口,根据面向接口编程原则,可以使用被代理类的地方,统统可以用代理类代替,同时类内部持有被代理类的引用,真正的业务处理逻辑可以交给被代理类去作。

2.3 普通代理模式的实现(静态代理)

假设我要写一个日志代理,在真实的业务方法调用前后各记一条日志,看看静态代理是怎么做的。

  • 业务接口
public interface IService {void service1();void service2();
}

接口含有两个抽象业务方法

  • 被代理类
public class RealService implements IService {@Overridepublic void service1() {System.out.println("service1");}@Overridepublic void service2() {System.out.println("service2");}
}

被代理类实现业务接口,并且重写了业务方法。

  • 日志代理
public class StaticLogProxy implements IService {private IService iService;public StaticLogProxy(IService iService) {this.iService = iService;}@Overridepublic void service1() {System.out.println("service1 start!");iService.service1();System.out.println("service1 end!");}@Overridepublic void service2() {System.out.println("service2 start!");iService.service2();System.out.println("service2 end!");}}
  • 运行结果

如上图所示,在业务方法执行前后分别记了一条日志,表示业务方法执行的开始和结束。我们的代理类成功对原有业务方法做了增强。但是静态代理存在以下问题:
1.代理类和被代理类耦合,适用性差。试想如果我希望为所有的业务类添加日志增强逻辑,那么岂不是要为几乎每个业务类编写代理类?这是不现实也是开发时无法接受的。
2.代理类的增强逻辑和业务逻辑过于耦合,不利于后期维护和扩展。从service1和service2中就可以看出,除了中间的业务处理不一样,代理类的处理逻辑是一样的,而我们竟然没有将其分离。
以上两点其实反映的是同一个问题:我们希望自己编写的代理类对所有业务类,所有业务方法都适用,而静态代理的泛用性太差了。问题的关键在于编写代理逻辑和业务逻辑分离的代理类,运行时才将其和具体的业务类绑定,对其业务方法做增强。为此,我们需要动态代理。动态代理的实现方式很多,下面以jdk自带的代理方式做说明。

3. JDK动态代理详解

3.1 JDK动态代理实现

  • 方法调用处理器
public class LogHandler implements InvocationHandler {//被代理对象private Object target;public LogHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(method.getName() + " start!");//前置处理Object res = method.invoke(this.target, args);//执行业务方法System.out.println(method.getName() + " end!");//后置处理return res;}
}

每一个代理对象都有一个与之关联的方法调用处理器,该处理器实现了InvocationHandler接口并重写了invoke方法。当我们调用代理对象的方法的时候,对该方法的调用会转交给方法调用处理器的invoke方法来执行,所以方法调用处理器的invoke方法是动态代理的核心。该方法内是通用的代理逻辑。在我们通过反射的方式通过被代理对象target执行业务逻辑的前后,可以对其作前置和后置增强。

  • 客户端代码
public class Client {public static void main(String[] args) {//1.创建被代理对象RealService realService = new RealService();//2.创建动态代理的方法调用处理器LogHandler logHandler = new LogHandler(realService);//3.创建动态代理对象IService service=(IService)Proxy.newProxyInstance(logHandler.getClass().getClassLoader(),realService.getClass().getInterfaces(),logHandler);service.service1();System.out.println("---------------");service.service2();}
}

第一步我们创建了被代理对象realService;第二步我们创建了动态代理的核心:方法调用处理器。因为处理器内部需要委托被代理对象去执行真正的业务方法,所以需要传入被代理对象作参数。第三步我们通过调用反射包下的Proxy类的静态方法去生成真正的代理对象。该方法的方法签名如下

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException

该方法含有三个参数
ClassLoader loader:指定加载的代理类的类加载器
Class<?>[] interfaces:指定代理类要实现的接口
InvocationHandler h:指定方法调用处理器
关于第二个参数可能要说明下,因为jdk的动态代理是针对接口的动态代理,代理类需要实现指定的业务接口,这里就是被代理类实现的那些接口。这样就能充分利用java多态特性,代码中所有能使用被代理对象的地方都能用代理对象进行替换。

  • 运行结果

和静态代理的运行结果一样。如果我们要对其他业务类使用日志代理,只需要修改下客户端代码就行,这是静态代理办不到的。具有良好的扩展性是动态代理相比静态代理最大的优势。

3.2 方法调用流程图

  • 1.客户端调用代理对象的业务方法,创建代理对象的时候传入了接口数组参数,故而代理对象也实现了业务接口。
  • 2.代理对象将请求转发给方法调用处理器的invoke方法
  • 3.方法调用处理器在invoke方法内部通过反射的方式调用被代理对象的业务方法

3.3 动态代理和静态代理的区别

  • 静态代理编译期生成代理类;动态代理运行期生成代理类。
  • 静态代理和被代理类及其业务逻辑耦合,适用性较差且代理逻辑难以扩展;动态代理可以在不知道被代理类的前提下编写代理逻辑,运行时才决定被代理对象,适用性好且代理逻辑易于扩展。

3.4 其他实现动态代理的方式

  • cglib面向类的动态代理
  • javaassist字节码操作库实现
  • asm

4. 总结

代理用以控制对对象的访问,本质上是对其功能提供某种形式的增强。按实现又可分为静态代理和动态代理。动态代理因其代理逻辑和业务逻辑相分离的特点,具有良好的适用性和可扩展性,是Spring中AOP的底层实现。

转载于:https://www.cnblogs.com/LoveShare/p/10796966.html

代理模式详解(静态代理和动态代理的区别以及联系)相关推荐

  1. cglib动态代理jar包_代理模式详解:静态代理+JDK/CGLIB 动态代理实战

    1. 代理模式 代理模式是一种比较好的理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标 ...

  2. java中的静态、动态代理模式以及Spring中的CgLib动态代理解读(面试必问)

    java中的静态.动态代理模式以及Spring中的CgLib动态代理解读(面试必问) 静态代理 动态代理 CgLib动态代理     基础知: 反射知识 代理(Proxy)是一种设计模式,提供了对目标 ...

  3. 静态代理与动态代理模式详解(优缺点分析,实例分析,读源码必备)

    1.代理模式 (1)概念 代理就是帮别人做事情,如:工厂的中介,中介负责为工厂招收工人,那么中介就是工厂的代理:客户通过商家购买东西,商家向厂家购买货物,商家就是工厂的代理 在开发中存在a类需要调用c ...

  4. Spring AOP理论 +代理模式详解

    目录 1.理解AOP 1.1.什么是AOP 1.2.AOP体系与概念 1.3.Spring AOP 通知的执行顺序 2.代理模式 2.1.静态代理 2.2.静态代理的缺点 3.动态代理 JDK 动态代 ...

  5. 代理模式详解(包含原理详解)

    http://www.cnblogs.com/zuoxiaolong/p/pattern3.html 作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为 ...

  6. 第四篇、代理模式详解(三种)

    一.代理模式 代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用.通俗的来讲代理模式就是我们生活中常见的中介. 二.代理模式的实现方式 1.静态代理 在代理之前,所有 ...

  7. (二)代理模式详解(包含原理详解)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处. 我特意将本系列改了下名字,原名是<设计模式学习之路>,原因是因为之前写过一篇<spring源码学习之路>,但是 ...

  8. java设计模式之代理模式详解

    代理模式在Java中十分常见,有如Spring实现AOP而使用动态代理,更有RPC实现中使用的调用端调用的代理服务.代理模型除了是一种设计模式之外,它更是一种思维,所以探讨并深入理解这种模型是非常有必 ...

  9. 软件设计模式——代理模式详解

    摘要 动态代理是Java语言中非常经典的一种设计模式,也是所有设计模式中最难理解的一种.那什么是代理设计模式?代理设计的基础概念就是通过代理控制对象的访问,可以在这个对象调用方法之前.调用方法之后去处 ...

最新文章

  1. map函数的简单用法。
  2. 一段在SAP C4C里触发S4HANA outbound Delivery的ABSL代码
  3. Linux压缩与解压常用命令
  4. python设计一个动物类_我用Python实现了12500张猫狗图像的精准分类
  5. Spring 依赖注入Dependency Injection
  6. DSB2017第一名代码尝试运行(记录自用)(一)
  7. 用Redis实现分布式锁 与 实现任务队列
  8. Windows平台下编译FFmpeg
  9. 算法设计思维导图(算法设计与分析第二版)
  10. 微软雅黑字体的bug,可能不是我第一个发现的
  11. 汽车车牌自动识别技术
  12. 如果看了此文你还不懂傅里叶变换,那就过来掐死我吧【完整版教程】
  13. 快手和抖音怎么打开微信小程序
  14. ie显示服务器拒接链接,IE浏览器拒接访问是怎么回事 IE浏览器显示拒接访问的有效解决方法...
  15. mysqladmin命令简介
  16. 一文搞懂什么是PWM!
  17. 拥有一套如何让客户购买的方法?
  18. 调用Tushare数据库绘制K线图
  19. 怎么用计算机画图工具,小编教你电脑自带画图软件如何打开
  20. C语言中动态分配数组

热门文章

  1. iOS sha1加密算法
  2. LeetCode Permutations
  3. C# 微支付退款申请接口 V3.3.6
  4. 我是如何实用:before :after
  5. ad network
  6. shell命令tree
  7. Vue 下拉刷新及无限加载组件 - 有你便是晴天 - 博客园
  8. python每天1道面试题(3)--字符串组合
  9. 数组去重的各种方式对比
  10. 分配的访问权限的展台应用:最佳做法