代理模式代理模式

目录

1、使用场景

2、静态代理

3、动态代理

JDK动态代理

CGlib 动态代理实现


1、使用场景

使用代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。

2、静态代理

NO.1 抽象接口:定义视频播放器接口Player

public interface Player {void loadVideo(String filename);void playVideo(String filename);
}

NO.2 真实类:定义接口实现类VPlayer

public class VPlayer implements Player {@Overridepublic void loadVideo(String filename) {System.out.println("加载MP4视频文件:"+filename);}@Overridepublic void playVideo(String filename) {System.out.println("播放MP4视频:"+filename);}
}

NO.3 代理类:定义代理类VPlayerProxy,实现同样的接口,并且引入目标对象

public class VPlayerProxy implements Player {private Player player;public VPlayerProxy(Player player) {this.player = player;}@Overridepublic void loadVideo(String filename) {player.loadVideo(filename);}@Overridepublic void playVideo(String filename) {player.playVideo(filename);}
}

NO.4 客户端调用

public class Client1 {public static void main(String[] args) {//直连方式Player vplay=new VPlayer();vplay.playVideo("aaa.mp4");System.out.println();//代理方式Player proxy=new VPlayerProxy(vplay);proxy.loadVideo("aaa.mp4");proxy.playVideo("aaa.mp4");}
}

3、动态代理

JDK动态代理

JDK动态代理是基于接口实现的代理,只能代理实现了接口的类。

在运行时动态生成一个代理对象,,同时还可以在方法调用前后执行额外的增强处理。JDK动态代理通过反射机制实现代理功能,其原理分为以下几个步骤:

(1)、创建实现InvocationHandler接口的代理类工厂:在调用Proxy类的静态方法newProxyInstance时,会动态生成一个代理类。
(2)、在代理对象的方法被调用时,JVM会自动调用代理类的invoke方法。在invoke方法中,可以根据需要执行各种逻辑,比如添加日志、性能统计、事务管理等。
(3)、invoke方法调用:在invoke方法中,通过反射机制调用目标对象的方法,并返回方法的返回值。在调用目标对象的方法前后,可以执行额外的逻辑。

通用实现代码

public class JDKProxyFactory implements InvocationHandler {//需要被代理的对象private Object object;public JDKProxyFactory(Object object) {this.object = object;}@SuppressWarnings("unchecked")public <T> T getProxy(){return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),//当前线程的上下文ClassLoaderobject.getClass().getInterfaces(), //代理需要实现的接口this); // 处理器自身}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;//进行方法匹配,调用对应方法名的方法if ("loadVideo".equals(method.getName())) {result=method.invoke(object, args);}if ("playVideo".equals(method.getName())) {System.out.println("前置增强");result=method.invoke(object, args);System.out.println("后置增强");}return result;}
}

客户端调用

public class Client2 {public static void main(String[] args) {Player player=new VPlayer();Player proxy=new JDKProxyFactory(player).getProxy();proxy.loadVideo("aaa.mp4");proxy.playVideo("aaa.mp4");/*      或者Player p=new VPlayer();Player o = (Player) Proxy.newProxyInstance(p.getClass().getClassLoader(),p.getClass().getInterfaces(),new VPlayerProxyFactory(p));o.loadVideo("aaaa.mp4");
*/}
}

CGlib 动态代理实现

CGlib方式是基于继承实现的代理,它不是指真实类需要继承某个父类,而是生成的代理类作为真实类的子类去代理父类,即代理类继承自真实类。这种方式不需实现接口,可以作为JDK代理方式的补充方案。

CGLIB(Code Generation Library)可以在运行时动态生成目标类的子类作为代理类,并覆盖其中的方法来实现代理功能。与Java自带的JDK动态代理不同,CGlib动态代理可以代理没有实现接口的类。其原理分为以下几个步骤:

(1)、创建Enhancer对象:Enhancer是CGLIB库中用于动态生成子类的主要类。通过创建Enhancer对象并设置需要代理的目标类、拦截器等参数,可以生成一个代理类。

 (2)、调用代理对象:通过调用代理对象的方法,会触发拦截器的intercept方法。在intercept方法中,可以根据需要执行各种逻辑,比如添加日志、性能统计、事务管理等。

单独定义一个没有接口的真实类APlayer

//音频播放器
public class APlayer {public void loadAudio(String filename) {System.out.println("加载MP3音频文件:"+filename);}public void playAudio(String filename) {System.out.println("播放MP3:"+filename);}
}

通用实现代码

public class CglibProxyFactory implements MethodInterceptor {@SuppressWarnings("unchecked")public <T> T getProxy(Class<T> clazz) {Enhancer en = new Enhancer();//设置代理的父类en.setSuperclass(clazz);//设置方法回调en.setCallback(this);//创建代理实例return (T)en.create();}@Override//参数中的object是目标对象,method和args是目标对象的方法和参数,methodProxy是方法代理public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Object result = null;if ("loadAudio".equals(method.getName())) {//通过继承的方法实现代理,因此这里调用invokeSuperresult = methodProxy.invokeSuper(object, args);}if ("playAudio".equals(method.getName())) {result = methodProxy.invokeSuper(object, args);}return result;}
}

客户端调用

public class Client3 {public static void main(String[] args) {APlayer aplayer=new APlayer();APlayer proxy = new CglibProxyFactory().getProxy(aplayer.getClass());//验证代理类的父类System.out.println("代理类的父类:"+proxy.getClass().getSuperclass().getSimpleName());System.out.println();proxy.loadAudio("荷塘月色.mp3");proxy.playAudio("荷塘月色.mp3");}
}

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

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

相关文章

http1,https,http2,http3总结

1.HTTP 当我们浏览网页时&#xff0c;地址栏中使用最多的多是https://开头的url&#xff0c;它与我们所学的http协议有什么区别&#xff1f; http协议又叫超文本传输协议&#xff0c;它是应用层中使用最多的协议&#xff0c; http与我们常说的socket有什么区别吗&#xff1f; …

怎么在电脑桌面上添加待办事项?

在电脑桌面上选择一款待办事项工具&#xff0c;可以高效率地督促各项任务的按时完成&#xff0c;大大地提高工作的效率&#xff0c;支持在电脑上安装待办事项的工具类型是比较多的&#xff0c;为更好的辅助日常办公&#xff0c;建议大家可以选择高效率辅助办公的电脑便签工具&a…

网络协议--TCP的未来和性能

24.1 引言 TCP已经在从1200 b/s的拨号SLIP链路到以太数据链路上运行了许多年。在80年代和90年代初期&#xff0c;以太网是运行TCP/IP最主要的数据链路方式。虽然TCP在比以太网速率高的环境&#xff08;如T2电话线、FDDI及千兆比网络&#xff09;中也能够正确运行&#xff0c;但…

高并发和存储之间的关系是什么?

文章目录 &#x1f50a;博主介绍&#x1f916;博主的简介&#x1f4e5;博主的目标 &#x1f964;本文内容&#x1f34a; 一、高并发对存储的压力&#x1f34a; 二、存储的性能和可扩展性 &#x1f4e2;总结 &#x1f50a;博主介绍 &#x1f4d5;我是廖志伟&#xff0c;一名Java…

[Unity+智谱AI开放平台]调用ChatGLM Tuobo模型驱动AI小姐姐数字人

1.简述 本篇文章主要介绍一下&#xff0c;在Unity端&#xff0c;集成智谱AI开放平台提供的chatglm模型api&#xff0c;实现AI聊天互动相关的功能。从智谱AI官方站点上看到&#xff0c;提供有chatglm turbo的公共模型服务&#xff0c;能够实现32K超长上下文&#xff0c;应用到我…

Spring Security 6.1.x 系列(3)—— 基于过滤器的基础原理(二)

四、SecurityFilterChain 在Serlvet中&#xff0c;一组Security Filter组成SecurityFilterChain&#xff0c;SecurityFilterChain的概念就比较好理解&#xff0c;是Spring Security 提供的过滤器链&#xff0c;用于管理本身所有的过滤器&#xff0c;在上面的流程图中已有说明。…

【嵌入式】Linux C编程——C要注意的东西

1、语法分析中的“贪心法”&#xff1a; 编译器将程序分解成符号的方法是&#xff0c;从左到右一个字符一个字符地读入&#xff0c;如果该字符可能组成一个符号&#xff0c;那么再读入下一个字符&#xff0c;判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分&…

Lvs+Nginx+NDS

什么是&#xff1f;为什么&#xff1f;需要负载均衡 一个网站在创建初期&#xff0c;一般来说都是只有一台服务器对用户提供服务 ​ 从图里可以看出&#xff0c;用户经过互联网直接连接了后端服务器&#xff0c;如果这台服务器什么时候突然 GG 了&#xff0c;用户将无法访问这…

Python构造代理IP池提高访问量

目录 前言 一、代理IP是什么 二、代理IP池是什么 三、如何构建代理 IP 池 1. 从网上获取代理 IP 地址 2. 对 IP 地址进行筛选 3. 使用筛选出来的 IP 地址进行数据的爬取 四、总结 前言 爬虫程序是批量获取互联网上的信息的重要工具&#xff0c;在访问目标网站时需要频…

QT实现用本地资源管理器来打开文件夹

QString path"文件夹路径";QDesktopServices::openUrl(QUrl("file:"path, QUrl::TolerantMode)); 在windows中QT编程&#xff0c;使用资源管理器来打开指定本地文件夹的方法&#xff1a; 第一种&#xff1a;使用Qprocess命令&#xff08;相当于在cmd命令管…

【面试经典150 | 链表】反转链表 II

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;迭代 其他语言python3 写在最后 Tag 【头插法】【迭代】【链表】 题目来源 92. 反转链表 II 题目解读 返回部分链表。 解题思路 方法一&#xff1a;迭代 我们首先需要找到开始反转链表的前一个节点&#xff0c;为此…

React 你还在用 Redux 吗?更简化的状态管理工具(Recoil)

以往传统的 Redux 状态管理工具使用起来代码太过于复杂。 你需要通过纯函数触发 action 再去修改 data 中定义的数据&#xff0c;而且要通过接口请求数据还需要借助 redux - think 这个中间件才能完成。。。 更加方便使用的工具&#xff1a;Recoil ~ 由 facebook 推出契合 R…

【机器学习可解释性】5.SHAP值的高级使用

机器学习可解释性 1.模型洞察的价值2.特征重要性排列3.部分依赖图4.SHAP 值5.SHAP值的高级使用 正文 汇总SHAP值以获得更详细的模型解释 总体回顾 我们从学习排列重要性和部分依赖图开始&#xff0c;以显示学习后的模型的内容。 然后我们学习了SHAP值来分解单个预测的组成部…

CSS3背景样式

在CSS 2.1中&#xff0c;background属性的功能还无法满足设计的需求&#xff0c;为了方便设计师更灵活地设计需要的网页效果&#xff0c;CSS3在原有background基础上新增了一些功能属性&#xff0c;可以在同一个对象内叠加多个背景图像&#xff0c;可以改变背景图像的大小尺寸&…

[ubuntu系统下的文本编辑器nano,vim,gedit,文件使用,以及版本更新问题]

文本编辑器概要 在Ubuntu系统下&#xff0c;有许多文本编辑器可供选择&#xff0c;每个编辑器都有其独特的特性和用途。以下是一些常见的文本编辑器&#xff1a; Gedit&#xff1a; 这是Ubuntu默认的文本编辑器&#xff0c;它简单易用&#xff0c;适合基本的文本编辑任务。 安…

前端基础---跳转相关的功能

后端给链接地址并且给token进行跳转 如果点击有key4&#xff0c;说明要跳转到相应的页面 auth是通过后端获取的地址&#xff0c; jdk是后端获取的相应的token&#xff0c; 然后进行拼接&#xff0c;进行window.open&#xff08;&#xff09;进行跳转 if (key 4) {var testUrl …

基于RFID技术的优化医药供应链管理解决方案

一、社会背景和挑战 随着全球假药问题的严重性日益凸显&#xff0c;医疗产品的追溯和管理变得越来越重要。据世界卫生组织报告&#xff0c;全球假药比例已超过10%&#xff0c;而中国每年至少有20万人死于假药和不当用药。在国际上&#xff0c;医疗产品的追溯体系已成为监管机构…

MLF - 麻辣粉

MLF全称中期借贷便利&#xff08;Medium-term lending Facility&#xff09;,理解为央行向商业银行、政策银行发放的贷款&#xff0c;但需要符合一定要求才可向央行申请。银行通过MLF向央行借款的时候&#xff0c;需要提供担保品。一般为国债、央行票据、政策性金融债、地方债、…

数据库的用户管理

一、创建用户&#xff1a;create user 二、赋予用户权限&#xff1a;grant&#xff08;终端执行&#xff09; 三、删除用户权限&#xff1a;revoke&#xff08;在终端操作&#xff09; 四、用户的重命名&#xff1a;rename 五、删除用户&#xff1a;drop 六、修改用户密码 1、…

linux目录与文件管理

目录与路径 关于执行文件路径的变量&#xff1a;$PATH ls完整文件名为&#xff1a;/bin/ls 在任何文件夹下输入ls命令可以显示出一些信息而不是找不到命令&#xff0c;这就是因为环境变量PATH所致。在执行命令时&#xff0c;系统会依照PATH的设置去每个PATH定义的目录下查找文…