首页 > 其他分享 >《深度解读代理模式:静态代理与动态代理的详尽剖析》

《深度解读代理模式:静态代理与动态代理的详尽剖析》

时间:2024-08-20 14:51:43浏览次数:11  
标签:对象 代理 详尽 剖析 卖票 TrainStation 动态 public

代理模式

一、引言

在 Java 开发中,代理模式是一种非常重要的设计模式,它为其他对象提供一种代理,以控制对这个对象的访问,在访问对象和目标对象之间起到中介作用。Java 中的代理按照代理类生成时机不同分为静态代理和动态代理,而动态代理又有 JDK 代理和 CGLib 代理两种。本文将详细探讨代理模式的概念、角色、静态代理与动态代理的实现以及它们的优缺点和对比。

二、代理模式的角色

  1. 抽象角色(Subject):通过接口或抽象类声明真实角色和代理对象实现的业务方法。
  2. 真实角色(Real Subject):实现了抽象角色中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  3. 代理角色(Proxy):提供了与真实角色相同的接口,其内部含有对真实角色的引用,它可以访问、控制或扩展真实角色的功能。

三、静态代理

静态代理的定义:静态代理就是指在给一个类扩展功能的时候,书写一个静态的类,相当于在之前的类上套了一层,在不改变之前的类的前提下对原有功能进行扩展。静态代理需要代理对象和目标对象实现一样的接口。

// 高铁站接口,有卖票功能
public interface TrainStation {
    /**
     * 卖票方法
     */
    void sellTickets();
}

// 西安高铁站卖票
public class GuangzhouTrainStation implements TrainStation {
    @Override
    public void sellTickets() {
        System.out.println("西安高铁站卖票啦");
    }
}

// 代售点卖票(代理类)
public class ProxyPoint implements TrainStation {
    // 目标对象(代理高铁站售票)
    private TrainStation station = new GuangzhouTrainStation();

    @Override
    public void sellTickets() {
        // 代售加收 5%手续费
        System.out.println("代售加收 5%手续费");
        // 调用目标对象的卖票方法
        station.sellTickets();
    }

    public static void main(String[] args) {
        ProxyPoint proxyPoint = new ProxyPoint();
        // 代售加收 5%手续费
        // 西安高铁站卖票啦
        proxyPoint.sellTickets();
    }
}

静态代理的优缺点

  • 优点:实现简单,容易理解,只要确保目标对象和代理对象实现共同的接口或继承相同的父类就可以在不修改目标对象的前提下进行扩展。
  • 缺点:代理类和目标类必须有共同接口 (父类),并且需要为每一个目标类维护一个代理类,当需要代理的类很多时会创建出大量代理类。一旦接口或父类的方法有变动,目标对象和代理对象都需要作出调整。

四、动态代理

动态代理的定义:代理类在代码运行时创建的代理称之为动态代理。动态代理中代理类并不是预先在 Java 代码中定义好的,而是运行时由 JVM 动态生成,并且可以代理多个目标对象。

  1. JDK 动态代理

JDK 动态代理是 Java JDK 自带的一个动态代理实现,位于 java.lang.reflect 包下。

// 高铁站接口,有卖票功能
public interface TrainStation {
    /**
     * 卖票方法
     */
    void sellTickets();
}

// 西安高铁站卖票
public class GuangzhouTrainStation implements TrainStation {
    @Override
    public void sellTickets() {
        System.out.println("西安高铁站卖票啦");
    }
}

// 北京高铁站卖票
public class ShenzhenTrainStation implements TrainStation {
    @Override
    public void sellTickets() {
        System.out.println("北京高铁站卖票啦");
    }
}

// 代售点卖票(代理类)
public class ProxyPoint implements InvocationHandler {
    private TrainStation trainStation;

    /**
     * 获取代理对象的方法
     * @param trainStation 目标对象
     * @return 代理对象
     */
    public TrainStation getProxyObject(TrainStation trainStation) {
        this.trainStation = trainStation;
        Class<? extends TrainStation> clazz = trainStation.getClass();
        return (TrainStation) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 代售高铁票收取 5%手续费
        System.out.println("代售高铁票收取 5%手续费");
        // 调用目标对象的方法
        return method.invoke(this.trainStation, args);
    }
}

JDK 动态代理的优缺点

  • 优点:使用简单、维护成本低;Java 原生支持,不需要任何依赖;解决了静态代理存在的多数问题。
  • 缺点:由于使用反射,性能会比较差;只支持接口实现,不支持继承,不满足所有业务场景。
  1. CGLib 动态代理

CGLib 是一个强大的、高性能的代码生成库。它可以在运行期扩展 Java 类和接口,其被广泛应用于 AOP 框架中(Spring、dynaop)中,用以提供方法拦截。CGLib 比 JDK 动态代理更强的地方在于它不仅可以接管 Java 接口,还可以接管普通类的方法。

首先在项目中引入 CGLib 依赖:

<!-- 先引入 cglib 包 -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>${cglib-version}</version>
</dependency>

代理类代码如下:

// 代售点卖票(代理类)
public class ProxyPoint implements MethodInterceptor {
    /**
     * 获取代理对象的方法
     * @param trainStation 目标对象的类
     * @return 代理对象
     */
    public TrainStation getProxyObject(Class<? extends TrainStation> trainStation) {
        // 创建 Enhancer 对象,类似于 JDK 动态代理的 Proxy 类,下一步就是设置几个参数
        Enhancer enhancer = new Enhancer();
        // 设置父类的字节码对象
        enhancer.setSuperclass(trainStation);
        // 设置回调函数
        enhancer.setCallback(this);
        // 创建代理对象并返回
        return (TrainStation) enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        // 代售高铁票收取 5%手续费
        System.out.println("代售高铁票收取 5%手续费");
        // 调用父类(目标对象)的方法
        return methodProxy.invokeSuper(o, objects);
    }
}

五、总结

  1. 应用场景:
    • 保护目标对象。
    • 增强目标对象。
  2. 优点:
    • 代理模式能将代理对象与真实被调用的目标对象分离。
    • 一定程度上降低了系统的耦合程度,易于扩展。
    • 代理可以起到保护目标对象的作用。
    • 增强目标对象的职责。
  3. 缺点:
    • 代理模式会造成系统设计中类的数目增加。
    • 在客户端和目标对象之间增加了一个代理对象,请求处理速度变慢。
    • 增加了系统的复杂度。
  4. 两种动态代理的对比:
    • JDK 动态代理的特点:
      • 需要实现 InvocationHandler 接口,并重写 invoke 方法。
      • 被代理类需要实现接口,它不支持继承。
      • JDK 动态代理类不需要事先定义好,而是在运行期间动态生成。
      • JDK 动态代理不需要实现和被代理类一样的接口,所以可以绑定多个被代理类。
      • 主要实现原理为反射,它通过反射在运行期间动态生成代理类,并且通过反射调用被代理类的实际业务方法。
    • CGLib 的特点:
      • CGLib 动态代理中使用的是 FastClass 机制。
      • CGLib 生成字节码的底层原理是使用 ASM 字节码框架。
      • CGLib 动态代理需创建 3 份字节码,所以在第一次使用时会比较耗性能,但是后续使用较 JDK 动态代理方式更高效,适合单例 bean 场景。
      • CGLib 由于是采用动态创建子类的方法,对于 final 方法,无法进行代理。

标签:对象,代理,详尽,剖析,卖票,TrainStation,动态,public
From: https://blog.csdn.net/qq_67028830/article/details/141358773

相关文章

  • 《深入剖析原型模式:浅克隆、深克隆与单例模式的碰撞》
    3.原型模式一、引言在Java编程中,原型模式(Prototype)是一种创建对象的方式,通过拷贝原型实例来创建新的对象,为对象的创建提供了一种高效且灵活的途径。本文将详细探讨原型模式的概念、包含的角色、浅克隆与深克隆的实现,以及克隆对单例模式的影响和相应的解决办法。二、原......
  • 设计模式之cglib动态代理
    什么是动态代理呢?动态代理就是在java进程运行时,通过字节码技术,动态的生成某个类的代理类。在这个代理类中,我们可以做一些额外的操作,一方面仍然保持原有的方法的能力,另外一方面还增强了这些能力。听着是不是AOP有点像,没错,动态代理就是AOP的技术基石。在这之前我曾经写过两篇相关的......
  • C++第十一弹 -- STL之List的剖析与使用
    文章索引前言1.list的介绍2list的使用2.1list的构造函数2.2iterator的使用2.3listcapacity2.4listelementaccess2.5listmodifiers3.list的迭代器失效4.list与vector的对比总结前言本篇我们旨在探讨对于STL中list的使用,下一篇我们将会对list进行底层......
  • Docker compose 部署前后端-----采用nginx代理,支持一个端口部署多个前端
    Dockercompose部署前后端-----采用nginx代理,支持一个端口部署多个前端1、Linux服务器安装最新版docker,确保有dockercompose命令2、创建docker工作区目录mkdirdocker-workspace3、进入docker工作区目录,创建前端nginx目录,创建后端xxx目录mkdirnginxxxx4、创建confi......
  • 百度网盘代理怎么做?稳定收益,月入五位数
    在当前数字化时代,度盘作为一种流行的云存储服务,为用户提供了便捷、高效的数据存储和分享解决方案。然而,随着用户需求的不断增长,传统的网盘运营模式已无法满足部分用户的特殊需求。因此,度盘代理业务应运而生,它通过全新的思路和创新的策略,为代理商带来了稳定的收益,甚至实现了月入......
  • WindowsServer系统下nginx代理问题
    部署vue打包后的dist文件夹后,重启nginx发现没生效,操作如下:1.停止redis,删除浏览器缓存并用无痕模式访问发现依然不生效,试着各种办法重新导入数据库数据也不行,nginx.exe-sstop依然能访问2.搜索发现可能是WindowsServer系统的问题,于是执行命令nginx-squit退出nginx......
  • 深度剖析:低代码开发平台的兴起、优势与挑战
    【若您对内容感兴趣,可以联系或关注我们】引言近年来,“低代码”开发平台如雨后春笋般涌现,承诺让非专业人士也能快速构建应用程序。这种新兴技术正在挑战传统软件开发模式,引发了IT行业的广泛讨论。低代码平台是提高效率的利器,还是降低了编程门槛导致质量下降?它会改变开发者的工......
  • 企业 ERP 上云的利与弊:深度剖析与明智抉择
    【若您对内容感兴趣,可以联系或关注我们】引言在数字化浪潮汹涌的当下,企业系统与数据的上云已势不可挡,其中ERP系统的上云更是成为众多企业关注的焦点。本文将深入探讨企业ERP上云服务器的利与弊,助力企业在这一关键决策上洞察秋毫,做出最符合自身发展的明智选择。利:成本优......
  • 详尽 | Deeplabv3+结构理解
    https://arxiv.org/pdf/1802.02611.pdfhttps://link.springer.com/chapter/10.1007/978-3-319-10578-9_23目录Deeplabv3+Encoder部分Decoder部分补充摘要SPP 空间金字塔池化层模块Dilated/AtrousConv空洞卷积Deeplabv3+deeplab-v3+是语义分割网络,组合采用空洞......
  • 深入了解SOCKS5代理:全面指南
    在现代数字世界中,互联网隐私和性能至关重要。SOCKS5代理服务器因其独特的功能和灵活性,成为提高网络安全和性能的热门选择。本文旨在深入探讨SOCKS5代理服务的工作原理、优势及其在实际应用中的表现,帮助您快速了解如何最大限度地利用这一工具。如何理解SOCKS5代理服务器SOCKS......