设计模式——代理模式(Proxy Pattern)

概述

       代理模式是指为其他对象提供一种代理,以控制对这个对象的访问。代理对象在访问对象和目标对象之间起到中介作用。代理对象也可以在不修改目标对象的前提下,提供额外的功能操作,拓展目标对象的功能,比如说在目标对象的某个方法执行前后你可以增加一些自定义的操作。

       Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期就生成,而动态代理代理类则是在Java运行时动态生成。动态代理又有JDK代理和CGLib代理两种。

       代理(Proxy)模式分为三种角色:

    抽象角色(Subject): 通过接口或抽象类声明真实角色和代理对象实现的业务方法。

    真实角色(Real Subject): 实现了抽象角色中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。

    代理角色(Proxy) : 提供了与真实角色相同的接口,其内部含有对真实角色的引用,它可以访问、控制或扩展真实角色的功能。

代理模式结构图如下所示:

静态代理

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

  1. 定义一个接口及其实现类;
  2. 创建一个代理类同样实现这个接口
  3. 将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。

这样的话,我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情。

抽象主题类声明了真实主题类和代理类的公共方法,它可以是接口、抽象类或具体类,客户端针对抽象主题类编程,一致性地对待真实主题和代理主题,典型的抽象主题类代码如下:

真实主题类继承了抽象主题类,提供了业务方法的具体实现,其典型代码如下:

代理类也是抽象主题类的子类,它维持一个对真实主题对象的引用,调用在真实主题中实现的业务方法,在调用时可以在原有业务方法的基础上附加一些新的方法来对功能进行扩充或约束,最简单的代理类实现代码如下:

可以从上面代码看到,我们访问的是ProxyStation对象,也就是说ProxyStation是作为访问对象和目标对象的中介的,同时也对saleTickets方法进行了增强与扩展(代理点收取加收5%手续费)。

       静态代理的优点是实现简单,容易理解,只要确保目标对象和代理对象实现共同的接口或继承相同的父类就可以在不修改目标对象的前提下进行扩展。

而缺点也比较明显,那就是代理类和目标类必须有共同接口(父类),并且需要为每一个目标类维护一个代理类,当需要代理的类很多时会创建出大量代理类。一旦接口或父类的方法有变动,目标对象和代理对象都需要作出调整。

动态代理

       代理类在代码运行时创建的代理称之为动态代理,相比于静态代理来说,动态代理更加灵活。我们不需要针对每个目标类都单独创建一个代理类,并且也不需要我们必须实现接口,我们可以直接代理实现类(CGLIB 动态代理机制)。从 JVM 角度来说,动态代理中代理类并不是预先在Java代码中定义好的,而是运行时由JVM动态生成,并且可以代理多个目标对象。动态代理是在 运行时 动态生成类字节码,并加载到 JVM 中的。说到动态代理,Spring AOP、RPC 框架应该是两个不得不提的,它们的实现都依赖了动态代理。动态代理在我们日常开发中使用的相对较少,但是在框架中的几乎是必用的一门技术。学会了动态代理之后,对于我们理解和学习各种框架的原理也非常有帮助。就 Java 来说,动态代理的实现方式有很多种,比如 JDK 动态代理、CGLIB 动态代理 等等。

JDK动态代理

JDK动态代理是Java JDK自带的一个动态代理实现, 位于java.lang.reflect包下。在 Java 动态代理机制中 InvocationHandler 接口和 Proxy 类是核心。Proxy类中使用频率最高的方法是:newProxyInstance() ,这个方法主要用来生成一个代理对象。

这个方法一共有 3 个参数:

  1. loader :类加载器,用于加载代理对象。
  2. interfaces : 被代理类实现的一些接口;
  3. h : 实现了 InvocationHandler 接口的对象;

要实现动态代理的话,还必须需要实现InvocationHandler 来自定义处理逻辑。
当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler 接口类的 invoke 方法来调用。

invoke() 方法有下面三个参数:

  1. proxy :动态生成的代理类
  2. method : 与代理类对象调用的方法相对应
  3. args : 当前 method 方法的参数

JDK动态代理使用步骤

1、定义一个接口及其实现类;

2、自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;

3、通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象;

接口及实现类同静态代码,主要看下代理类:

优点:

  • 使用简单、维护成本低。
  • Java原生支持,不需要任何依赖。
  • 解决了静态代理存在的多数问题。

缺点:

  • 由于使用反射,性能会比较差。
  • 只支持接口实现,不支持继承, 不满足所有业务场景。
CGLIB动态代理

介绍JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类。 为了解决这个问题,我们可以用 CGLIB动态代理机制来避免。CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。

CGLIB通过继承方式实现代理。很多知名的开源框架都使用到了CGLIB, 例如 Spring 中的 AOP模块中:如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理。

在 CGLIB 动态代理机制中MethodInterceptor 接口和 Enhancer 类是核心。你需要自定义 MethodInterceptor 并重写intercept 方法,intercept 用于拦截增强被代理类的方法。

    obj : 被代理的对象(需要增强的对象)

    method : 被拦截的方法(需要增强的方法)

    args : 方法入参

    proxy :用于调用原始方法

你可以通过 Enhancer类来动态获取被代理类,当代理类调用方法的时候,实际调用的是 MethodInterceptor 中的intercept 方法。

CGLIB动态代理使用步骤:

  1. 定义一个类;
  2. 自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似;
  3. 通过 Enhancer 类的 create()创建代理类。

不同于 JDK 动态代理不需要额外的依赖。CGLIB(Code Generation Library) 实际是属于一个开源项目,如果你要使用它的话,需要手动添加相关依赖。

<dependency>

  <groupId>cglib</groupId>

  <artifactId>cglib</artifactId>

  <version>3.3.0</version>

</dependency>

应用场景:

    保护目标对象。

    增强目标对象。

优点:

    代理模式能将代理对象与真实被调用的目标对象分离。

    一定程度上降低了系统的耦合程度,易于扩展。

    代理可以起到保护目标对象的作用。

    增强目标对象的职责。

缺点:

    代理模式会造成系统设计中类的数目增加。

    在客户端和目标对象之间增加了一个代理对象,请求处理速度变慢。

    增加了系统的复杂度。

JDK 动态代理和 CGLIB 动态代理对比

JDK动态代理的特点:

    需要实现InvocationHandler接口, 并重写invoke方法。

    被代理类需要实现接口, 它不支持继承。

    JDK 动态代理类不需要事先定义好, 而是在运行期间动态生成。

    JDK 动态代理不需要实现和被代理类一样的接口, 所以可以绑定多个被代理类。

    主要实现原理为反射, 它通过反射在运行期间动态生成代理类, 并且通过反射调用被代理类的实际业务方法。

cglib的特点:

    cglib动态代理中使用的是FastClass机制。

    cglib生成字节码的底层原理是使用ASM字节码框架。

    cglib动态代理需创建3份字节码,所以在第一次使用时会比较耗性能,但是后续使用较JDK动态代理方式更高效,适合单例bean场景。

    cglib由于是采用动态创建子类的方法,对于final方法,无法进行代理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/256414.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 1901. 寻找峰值 II:二分查找

【LetMeFly】1901.寻找峰值 II&#xff1a;二分查找 力扣题目链接&#xff1a;https://leetcode.cn/problems/find-a-peak-element-ii/ 一个 2D 网格中的 峰值 是指那些 严格大于 其相邻格子(上、下、左、右)的元素。 给你一个 从 0 开始编号 的 m x n 矩阵 mat &#xff0c…

C#调用阿里云接口实现动态域名解析,支持IPv6(Windows系统下载可用)

电信宽带一般能申请到公网IP&#xff0c;但是是动态的&#xff0c;基本上每天都要变&#xff0c;所以想到做一个定时任务&#xff0c;随系统启动&#xff0c;网上看了不少博文很多都支持IPv4&#xff0c;自己动手写了一个。 &#xff08;私信可全程指导&#xff09; 部署步骤…

20231218在Ubuntu18.04下以EXT4格式化HDD

20231218在Ubuntu18.04下以EXT4格式化HDD 2023/12/18 17:24 缘起&#xff1a; 编译一个Android10大概要200GB&#xff0c;编译10个Android10的SDK&#xff0c;3TB的HDD机械硬盘就估计会被填满了&#xff01; 如果使用rm -rf *这个命令将SDK一个一个逐个地删除&#xff0c;估计2…

强大的电子书阅读器:OmniReader Pro for mac

&#x1f50d; OmniReader Pro 是一款专为 Mac 设计的强大阅读工具&#xff0c;它能够帮助你更高效地阅读和处理各种文本内容。无论是电子书、新闻文章、网页文本还是文件资料&#xff0c;OmniReader Pro 都能胜任&#xff01; ✅ OmniReader Pro 提供了丰富的功能&#xff0c…

UE5 C++(六)— 枚举UENUM、结构体USTRUCT和补充属性说明符

文章目录 枚举&#xff08;ENUM&#xff09;第一种方式第二种方式 结构体&#xff08;USTRUCT&#xff09;补充属性说明符&#xff08;ExposeOnSoawn&#xff09;结构体创建数据表格 枚举&#xff08;ENUM&#xff09; 第一种方式 定义枚举 UENUM(BlueprintType) namespace …

java配置+J_IDEA配置+git配置+maven配置+基本语句

当前目录文件夹dir 进入文件夹cd 返回上一级cd.. 创建文件夹&#xff1a;mkdir 文件名删除文件夹&#xff1a;rd 文件夹名&#xff0c; 目录不为空不能直接删 rd /s 带子文件夹一起删 清屏cls 切换d盘才能进入 下载git地址&#xff1a; Git - Downloading Package (g…

Linux网络编程(一):网络基础(上)

参考引用 UNIX 环境高级编程 (第3版)嵌入式Linux C应用编程-正点原子 1. 网络通信概述 网络通信本质上是一种进程间通信&#xff0c;是位于网络中不同主机上的进程之间的通信&#xff0c;属于 IPC 的一种&#xff0c;通常称为 socket IPC&#xff0c;网络通信是为了解决在网络…

德思特EMC RICI测试方案助您对抗电磁设备干扰!

来源&#xff1a;德思特测试测量 德思特方案丨德思特EMC RICI测试方案助您对抗电磁设备干扰&#xff01; 原文链接&#xff1a;https://mp.weixin.qq.com/s/D8wdQr_reaFG-yppT8nzkw 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; 方案背景 电磁或射频干扰的敏感性&…

【AIGC重塑教育】AI大模型驱动的教育变革与实践

文章目录 &#x1f354;现状&#x1f6f8;解决方法✨为什么要使用ai&#x1f386;彩蛋 &#x1f354;现状 AI正迅猛地改变着我们的生活。根据高盛发布的一份报告&#xff0c;AI有可能取代3亿个全职工作岗位&#xff0c;影响全球18%的工作岗位。在欧美&#xff0c;或许四分之一…

(八)STM32 USART —— 串口通讯

目录 1. 串口通讯协议简介 1.1 物理层 1.1.1 电平标准 1&#xff09;TTL 电平 2&#xff09;RS-232 电平 3&#xff09;RS-485 电平 4&#xff09;CAN 总线电平 1.1.2 USB 和 串口 的区分 1.1.3 RS-232 信号线 1.2 协议层 1&#xff09;波特率 2&#xff09;通讯…

Arcgis中利用模型构建器统一栅格数据的行列号

1、统一&#xff08;X,Y) 方法&#xff1a;"数据管理工具箱"→"Projections and Transformations"→"Raster"→"Project Raster" 构建模型 这里以行列号最小的栅格&#xff08;X,Y&#xff09;为准&#xff08;其实也就是栅格数据的空…

数据可视化---离群值展示

内容导航 类别内容导航机器学习机器学习算法应用场景与评价指标机器学习算法—分类机器学习算法—回归机器学习算法—聚类机器学习算法—异常检测机器学习算法—时间序列数据可视化数据可视化—折线图数据可视化—箱线图数据可视化—柱状图数据可视化—饼图、环形图、雷达图统…

全球通关第一人,分享阿里云新版ACE认证备考攻略~

2022.3月底阿里云针对老版ACE进行了改版&#xff0c;针对云计算技术的发展趋势&#xff0c;新增了云原生等热门技术&#xff0c;同时新版ACE认证新增了实验和面试&#xff0c;全面考查考生的动手能力和理论知识结构&#xff0c;含金量大大提升。 作为阿里云新版ACE全球通关第一…

【智慧之窗】AI驱动产品探索

一.初识 ChatGPT ChatGPT 是由 OpenAI 开发的自然语言处理&#xff08;NLP&#xff09;模型&#xff0c;基于 GPT&#xff08;Generative Pre-trained Transformer&#xff09;架构。GPT 系列的模型旨在理解和生成自然语言文本。ChatGPT 专注于支持对话性任务&#xff0c;即与…

【remb】twcc 与remb的切换测试

500000bps 70kBps 1 000 000 bps后&#xff0c;图像清晰些了&#xff0c;但在mesh下还是会牺牲了它的及时性&#xff1b;上面的几种情况的延时性很大啊&#xff0c;有流畅度&#xff0c;但延时太大 在twcc策略下&#xff0c;我们看到 220kBps时即大概1.6M时&#xff0c;视频才…

【Spring】09 BeanClassLoaderAware 接口

文章目录 1. 简介2. 作用3. 使用3.1 创建并实现接口3.2 配置 Bean 信息3.3 创建启动类3.4 启动 4. 应用场景总结 Spring 框架为开发者提供了丰富的扩展点&#xff0c;其中之一就是 Bean 生命周期中的回调接口。本文将聚焦于其中的一个接口 BeanClassLoaderAware&#xff0c;介…

Day65力扣打卡

打卡记录 寻找峰值 II&#xff08;二分&#xff09; 链接 class Solution:def findPeakGrid(self, mat: List[List[int]]) -> List[int]:l, r 0, len(mat) - 1while l < r:mid (l r) // 2mx max(mat[mid])if mx > mat[mid 1][mat[mid].index(mx)]:r midelse:l…

外包干了6个月,技术退步明显.......

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…

xcrun: error: invalid active developer path

macOS升级完成后出现 xcrun: error: invalid active developer path问题。 xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun这是由于 Xcode command line tools 丢…

Web开发:如何在Visual Studio2022中使用Codeium(AI)编写代码

一、安装 【此款AI】免费&#xff01;免费&#xff01;免费&#xff01;使用时正常上网即可&#xff01; 1.前提条件 VS2022版本在17.5.5版本以上&#xff08;若版本不够则需要先更新&#xff09;安装和注册需要科学上网&#xff0c;使用则正常上网即可 2.开始下载扩展 方法…