设计模式 - 结构型模式考点篇:代理模式(静态代理、JDK 动态代理、CGLIB 动态代理)

news/2024/5/15 12:29:12/文章来源:https://blog.csdn.net/CYK_byte/article/details/133683628

目录

一、代理模式

一句话概括

1.1、代理模式概述

1.2、静态代理

1.3、JDK 动态代理

1.4、CGLIB 动态代理

1.5、对比三种代理

1.5.1、jdk 代理 VS CGLIB 代理

1.5.2、动态代理 VS 静态代理

1.6、优缺点

1.7、使用场景


一、代理模式


一句话概括

教你将类和对象结合再一起形成一个更强大的结构.

1.1、代理模式概述

由于一些原因,我们不能直接访问目标对象,这时候需要提供一个目标对象的代理,通过代理来实现对目标对象的访问.

比如,我要去买火车票,就需要在火车触发的前几天坐车去火车站买票,相当的麻烦.  但是还有一种方式,就是我们可以直接在 12306 网站上直接进行买票,十分方便,这里的  12306 网站就相当于 代理.

代理模式分为以下三种角色:

  • 抽象主题类:通过接口或者抽象类声明真实主题要干的事情(业务).
  • 真实主题类:实现了抽象主题中的具体业务.
  • 代理类:内部包含 真实主题类 的实例对象,可以访问和扩展真实主题的功能.

1.2、静态代理

静态代理表示在编译期间就创建好了代理对象.

这里还是使用刚刚提到的火车站买票的案例来实现.

/*** 抽象主题:卖票接口*/
public interface SellTickets {void sell();}
/*** 真实主题类:火车站*/
public class TrainStation implements SellTickets{@Overridepublic void sell() {System.out.println("火车站卖票");}}
/*** 代理类:代售点(例如 12306 网站)*/
public class ProxyPoint {//在编译时期对象就创建好了,因此是静态代理private TrainStation trainStation = new TrainStation();public void sell() {System.out.println("方便了你,我自然要收取代理费用");trainStation.sell();}}
/*** 测试类*/
public class Client {public static void main(String[] args) {//直接就可以通过代理类买到票,不用再去火车站了ProxyPoint proxyPoint = new ProxyPoint();proxyPoint.sell();}}

这里就可以看出测试类是通过 ProxyPoint 类访问到的目标方法,同时也对 sell 方法进行了增强(例如:收取代理费用).

Ps:JDK 动态代理要求必须要定义接口,因为他就是对接口进行代理的.

1.3、JDK 动态代理

动态代理就是在程序运行期间,动态的在内存中创建出代理类(静态代理是在编译期间创建出代理类).

Java 中提供类一个动态代理类 Proxy(并不是 静态代理 中所说的代理对象类),提供了创建代理对象的静态方法(Proxy.newProxyInstance 方法)来获取代理对象.

这里继续使用买火车票案例

/*** 抽象主题:卖票接口*/
public interface SellTickets {void sell();}
/*** 真实主题类:火车站*/
public class TrainStation implements SellTickets {@Overridepublic void sell() {System.out.println("火车站卖票");}}
/*** 代理类工厂(不是代理类):用来创建代理对象*/
public class ProxyFactory {private TrainStation station = new TrainStation();public SellTickets getProxyObject() {//使用 Proxy 获取代理对象//newProxyInstance 参数如下://ClassLoader loader: 类加载器,此处填写真实对象的类加载器,是用来加载代理类的.//Class<?>[] interfaces: 填写真实对象实现的接口//InvocationHandler h: 代理对象要处理的业务逻辑SellTickets sellTickets = (SellTickets) Proxy.newProxyInstance(station.getClass().getClassLoader(),station.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//proxy: 代理对象,此方法中一般不用//method: 对应于在代理对象上调用的接口方法的 Method 实例//args: 代理对象调用接口方法时传递的实际参数System.out.println("收取代理费用(JDK 动态代理)");//执行真实对象Object result = method.invoke(station, args);return result;}});return sellTickets;}}
    public static void main(String[] args) {ProxyFactory factory = new ProxyFactory();//获取代理对象SellTickets proxyObject = factory.getProxyObject();proxyObject.sell();}

执行流程如下:

  1. 在测试类中通过代理对象调用 sell 方法.
  2. 此处执行的是代理类中的 sell 方法,因为此方法的对象来自于 JDK 的 Proxy.newProxyInstance 方法生成的.
  3. 代理类中的 sell 方法有调用了 InvocationHandler 接口的子实现类对象的 invoke 方法.
  4. invoke 方法底层(这里的源码可以通过阿里巴巴开源的诊断工具 Arthas 看到代理类的结构)通过反射执行了真实主题类中的 sell 方法.

1.4、CGLIB 动态代理

同样是买火车票案例,如果没有定义  SellTickets 这个 抽象主题类,只定义了 TrainStation 火车列类,很显然 JDK 代理就无法使用了,因为 JDK 动态代理要求必须定义接口,对接口进行代理.

CGLIB 是一个功能强大,高性能的代码生成包. 他为没有实现接口的类提供了代理,给 JDK 动态代理提供了很好的补充.

CGLIB 是第三方提供的包,因此需要引入 jar 包.

        <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2.2</version></dependency>

具体实现如下:

/*** 火车站*/
public class TrainStation {public void sell() {System.out.println("火车站卖票");}}
public class ProxyFactory implements MethodInterceptor {private TrainStation station = new TrainStation();public TrainStation getProxyObject() {//1.创建 Enhancer 对象,类似于 JDK 动态代理 Proxy 类Enhancer enhancer = new Enhancer();//2.设置父类(代理类的父类就是被代理类)的字节码对象enhancer.setSuperclass(station.getClass());//3.设置回调函数enhancer.setCallback(this);//4.创建代理对象TrainStation obj = (TrainStation) enhancer.create();return obj;}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {//这里的参数就和 JDK 动态代理的 invoke 很像了//o: 代理对象//method: 真实主题中的方法的 Method 实例//objects: 实际参数//methodProxy: 代理对象中的 method 实例System.out.println("收取代理费用(CGLIB 动态代理)");Object result = method.invoke(station, objects);return result;}}
public class Client {public static void main(String[] args) {//创建代理类工厂ProxyFactory factory = new ProxyFactory();//获取代理对象TrainStation proxyObject = factory.getProxyObject();//调用代理对象中的 sell 方法proxyObject.sell();}}

1.5、对比三种代理

1.5.1、jdk 代理 VS CGLIB 代理

  1. CGLIB 底层使用 ASM 字节码生成框架(这个不用去了解),使用字节码技术生成代理类,在 JDK 1.7 之前要比 Java 反射效率要高.  但是 CGLIB 不能对声明为 final 的类和方法进行处理,因为 CGLIB 的原理就是动态生成被代理类(真实主题类)的子类.
  2. 在 JDK 1.8 之后,JDK 的代理效率要高于 CGLIB.  因此只要是有接口的,就是用 JDK 动态代理,没有接口的使用 CGLIB 代理.

1.5.2、动态代理 VS 静态代理

  1. 动态代理最大的好处就是 抽象主题类(接口) 中声明的所有方法都被转移到了一个地方集中处理(InvocationHandler.invoke).  这样,当接口的方法数目比较多的时候,就不需要像静态代理那样每一个方法都需要在代理类中再中转一次.
  2. 将来如果接口增加一个方法,静态代理除了所有实现类(真实主题类)需要实现这个方法外,还需要在代理类中实现此方法. 提高了代码的维护成本. 静态代理就不会出现此问题.

1.6、优缺点

优点

中介,保护:代理模式在客户端和目标对象之间起到一个中介的作用和保护目标对象的作用.

扩展:代理对象可以扩展目标对象的功能.

解耦合:代理模式对客户端和目标对象进行解耦.

缺点:

实现起来相对复杂.

1.7、使用场景

  1. 远程代理:在远程调用时,为了良好的代码设计和可维护性,可以将网络通信部分隐藏起来,只暴露非本地服务器一个接口(代理),通过这接口即可访问到远程服务提供的功能,不必关心过多的通信实现细节.
  2. 防火墙代理:当浏览器配置成代理功能时,防火墙就会将浏览器的请求转给网络,当网络返回相应时吗,代理服务器再把他转给你的浏览器.
  3. 权限代理:控制一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限.

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

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

相关文章

python代码封装二进制文件并使用C#调用方案

思路 首先使用Cython库将python代码生成二进制文件pyd&#xff0c;然后使用C#中的pythonnet的Nuget包来进行调用&#xff0c;python代码中可以使用第三方类库。 Cython使用 Cython的安装 在命令行中使用如下语句即可安装Cython pip install cythonpyd文件格式 Cython用于…

Java——StringBuffer类常用操作示例

Java——StringBuffer类常用操作 package com.yushifu.javaAPI;import java.sql.SQLOutput;//StringBuffer类&#xff08;字符串缓冲区&#xff09; //StringBuffer类与String的区别————StringBuffer的内容和长度都是可以改的 //StringBuffer类似于一个字符容器&#xff0…

【数据结构】栈和队列-- OJ

目录 一 用队列实现栈 二 用栈实现队列 三 设计循环队列 四 有效的括号 一 用队列实现栈 225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09; typedef int QDataType; typedef struct QueueNode {struct QueueNode* next;QDataType data; }QNode;typedef struct …

pdf文档内容提取pdfplumber、PyPDF2

测试pdfplumber识别效果好些&#xff1b;另外pdf这两个如果超过20多页就没法识别了&#xff0c;结果为空 1、pdfplumber 安装&#xff1a;pip install pdfplumber -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com代码&#xff1a; import pdfpl…

应用超高频RFID技术的银行款箱柜资产管理系统

背景概述 随着银行后台管理的集中化思路&#xff0c;对款箱的管理需要实现“安全、高效”的“管、控、营”一体化&#xff0c;传统的人工款箱管理模式和数据采集方式已无法满足银行管理的快速、准确要求&#xff0c;严重影响了银行整体运行效率。 传统的款箱管理存在以下问题…

数据结构 | (三) Stack

栈 &#xff1a;一种特殊的线性表&#xff0c;其 只允许在固定的一端进行插入和删除元素操作 。 进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO &#xff08; Last In First Out &#xff09;的原则。 压栈&#xff1a;栈…

【面试经典150 | 哈希表】赎金信

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;哈希表方法二&#xff1a;数组模拟哈希表 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带…

mp4视频太大怎么压缩变小?

mp4视频太大怎么压缩变小&#xff1f;确实&#xff0c;很多培训和教学都转向了线上模式&#xff0c;这使得我们需要下载或分享大量的在线教学视频。然而&#xff0c;由于MP4视频文件通常较大&#xff0c;可能会遇到无法打开或发送的问题。为了解决这个问题&#xff0c;我们可以…

网络安全(黑客)——自学

前言&#xff1a; 想自学网络安全&#xff08;黑客技术&#xff09;首先你得了解什么是网络安全&#xff01;什么是黑客 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“…

ToBeWritten之让响应团队参与并做好沟通

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…

【yolov系列:yolov7改进添加SE注意力机制】

yolo系列文章目录 学习视频&#xff1a; YOLOV7改进-添加注意力机制_哔哩哔哩_bilibili 文章目录 yolo系列文章目录一、SE注意力机制是什么&#xff1f;二、yolov7改进添加SE注意力机制1.首先从github粘贴SE.py2.复制109行的conv3.在sppc加注意力机制 三、添加注意力机制在Conc…

DM宣传单制作,利用在线模板,快速替换文字

如果你需要制作一批宣传单&#xff0c;但是时间很紧&#xff0c;而且没有专业的设计人员协助&#xff0c;那么你可以选择使用在线模板来快速制作宣传单。本文将介绍如何使用乔拓云平台&#xff0c;快速制作宣传单的方法。 步骤一&#xff1a;选择适合的在线制作工具 首先&…

【多线程案例】设计模式-单例模式

1.单例模式 什么是单例模式&#xff1f; 所谓单例&#xff0c;即单个实例。通过编码技巧约定某个类只能有唯一一个实例对象&#xff0c;并且提前在类里面创建好一个实例对象&#xff0c;把构造方法私有化&#xff0c;再对外提供获取这个实例对象的方法&#xff0c;&#xff0…

腾讯云/阿里云国际站免费账号:腾讯云国际站如何对象存储cos设置防盗链

简介 为了避免恶意程序使用资源 URL 盗刷公网流量或使用恶意手法盗用资源&#xff0c;腾讯云国际站给用户带来不必要的损失。腾讯云对象存储支持防盗链配置&#xff0c;建议您通过控制台的防盗链设置配置黑/白名单&#xff0c;来进行安全防护。 注意&#xff1a; 如果您访问对…

北京筑龙全面赋能!打造公共资源交易一体化整合“内蒙模式”

近日&#xff0c; 由内蒙古自治区公共资源交易中心&#xff08;以下简称中心&#xff09;与北京筑龙联合建设的内蒙古公共资源交易平台一体化整合项目顺利完成验收工作。该平台的顺利验收标志着这个以科技创新和管理创新“双创”为驱动&#xff0c;以实现公共资源交易全流程电子…

Headless CMS(strapi)

Headless CMS(strapi) 玩了玩微信小程序的cms&#xff0c;感觉还挺好的&#xff0c;不过目前处于公测阶段&#xff0c;后续应该还是要收费的&#xff0c;不过这个操作还挺好的。文档地址 不过其获取图片的时候默认用到的是小城云开发环境的链接样式&#xff0c;如果用在公开网…

问题:remote: HTTP Basic: Access denied

参看文章&#xff1a;https://baijiahao.baidu.com/s?id1740126019873950482&wfrspider&forpc 解决方法一 (最有效) 输入&#xff1a;git config --system --unset credential.helper 再次进行 Git 操作&#xff0c;输入正确的用户名&#xff0c;密码即可。

Unity实现设计模式——策略模式

Unity实现设计模式——策略模式 策略模式是一种定义一些列算法的方法&#xff0c;这些所有的算法都是完成相同的工作&#xff0c;只是实现不同。它可以通过相同的方式调用所有的算法&#xff0c;减少各种算法类与使用算法类之间的耦合。 策略模式的 Strategy 类层次为 Contex…

用正则表达式验证用户名和跨域postmessage

正则验证用户名 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </hea…