当前位置: 首页 > news >正文

代理模式动态代理

什么是代理模式?

代理模式是开发中常见的一种设计模式,使用代理模式可以很好的对程序进行横向扩展。代理,顾名思义就是一个真实对象会存在一个代理对象,并且代理对象可以替真实对象完成相应操作,外部通过代理对象来访问真实对象并且还可以在代理对象中进行额外操作的扩展。

代理模式的特征是拥有接口、代理类、被代理类。并且代理类与被代理类同时实现该接口。代理类与被代理类之间通常存在一定关联,设计时会在代理类中注册一个被代理类的对象用于调用代理类的方法。这也印证了代理对象依然是执行的真实对象的方法

代理模式又分为静态代理和动态代理

静态代理

静态代理,关键字静态是指在程序运行之前编译时就已经确定了代理类、被代理类、接口。
下面列举两个示例展示静态代理:

  1. 学生通过班长交班费,班长作为学生的代理,学生是被代理,具有同一行为就是交班费,这个行为我们用接口进行约束

程序:

// 接口
public interface Person {void giveMoney();}
// 学生类--> 被代理类
public class Student implements Person{private String name;public Student(String name) {this.name = name;}public void giveMoney() {System.out.println(name+"同学上交50元班费");}
}
// 学生代理类
public class StuProxy implements Person{private Student stu;public StuProxy(Student stu) {if (stu.getClass() == Student.class) {this.stu = stu;}}public void giveMoney() {stu.giveMoney();}
}

测试:

public static void main(String[] args) {// 获取学生实例  Student stu = new Student("张三");// 学生找交钱给班长  学生找到代理StuProxy stuProxy = new StuProxy(stu);// 班长交给老师  代理交钱(交的是学生的钱)stuProxy.giveMoney();
}
  1. 房屋租赁,租客通过中介找房源,租客为被代理类,中介为代理类,接口声明租房方法
// 接口
public interface Rent {void doRent();}
// 被代理类
public class Renter implements Rent{public void doRent() {System.out.println("租客租房了");}
}
// 代理类
public class RentProxy implements Rent{private Renter renter;public RentProxy(Renter renter) {if (renter.getClass()==Renter.class)this.renter = renter;}public void doRent() {renter.doRent();}
}

测试:

public static void main(String[] args) {// 创建租客Renter renter = new Renter();// 租客找到中介RentProxy rentProxy = new RentProxy(renter);// 租客租房rentProxy.doRent();
}

上述两个示例,向代理类中注入被代理对象的方式都是通过构造器注入,当然也可以通过set方法注入

下面演示如果需要在已经编写好的代理类的输出中添加其他操作时的操作比如打印一个日志,在不修改源代码的情况下扩展

// 下面是最经典的Service层的写法
public interface UserService {void del();void select();
}
public class UserServiceImpl implements UserService{public void del() {System.out.println("删除操作");}public void select() {System.out.println("查询操作");}
}

假设现在我们需要在每一次执行操作前后打印一次执行日志,并且不能修改源代码那么就可以用到代理模式,将UserServiceImpl作为被代理类,扩展代理类如下:

public class UserServiceImplProxy implements UserService{private UserServiceImpl userService;// set注入public void setUserService(UserServiceImpl userService) {this.userService = userService;}public void del() {printLog();userService.del();}public void select() {printLog();userService.select();}private void printLog(){System.out.println("执行时间="+new Date());}
}

动态代理

动态代理:代理类在程序运行时被创建的代理方式。

关键在于动态,程序具有了动态特性,可以在运行期间根据不同的目标对象生成动态代理对象,并且可以通过动态代理对象对目标对象(真实对象)进行功能性补强。大白话来讲就是,可以在程序运行期间额外的对真实对象功能进行扩展。

此处的动态代理对象不是通过预先编写好的程序生成的,而是运行期间由于用户需求或者说是代码的指示生成的

动态代理分为两种:一类是基于接口实现的动态代理,另一类是基于类的动态代理
基于接口的动态代理–JDK动态代理通过反射完成,基于类实现的–>cglib

JDK动态代理核心:Proxy类、InvocationHandler接口、要参与代理的目标类必须实现对应接口,比如上述的Student必须实现Person接口。

继续以上述学生交班费为例,更改为动态代理模式:

JDK动态代理中间类:该类需要实现InvocationHandler接口

// JDK动态代理中间类
public class ProxyInvocationHandler implements InvocationHandler {// 被代理的对象private Object target;// ser方法注入参数public void setTarget(Object target) {this.target = target;}// 生成动态代理类public Object getProxy(){return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);}// 处理代理实例,并返回结果public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = method.invoke(target,args);return result;}
}

测试:

public static void main(String[] args) {// 获取真实角色Student stu = new Student("张三三");// 动态代理中间类对象InvocationHandlerProxyStudent proxyStudent = new InvocationHandlerProxyStudent();proxyStudent.setStu(stu);// 代理类实例Person proxy = (Person) proxyStudent.getProxy();// 代理类实例调用方法proxy.giveMoney();
}

上述程序,我们利用Proxy来生成代理类:

public Object getProxy(){return Proxy.newProxyInstance(this.getClass().getClassLoader(),
stu.getClass().getInterfaces(),this);
}

Proxy提供了静态的获取Proxy代理类的方法newProxyInstance,三个参数分别是1.类加载器 2.代理对象实现的接口 3. 调用处理程序(InvocationHandler)

在InvocationHandler官方文档就已经指出,每一个代理实例都关联有一个InvocationHandler调用处理程序,所以这里填this即可

在使用代理类的时候首先我们创建需要被代理的真实对象和动态代理中间类的对象,用set方法将真实对象交给中间类中的代理对象。在调用上述getProxy方法获取代理类。动态代理相对于静态代理有些难以理解,这是因为静态代理的代理类可以在程序中显式的被看到,而动态代理中的代理类文件是缓存在Java虚拟机,类名叫$Proxy0。

在虚拟机中生成的代理类中就会将我们所调用的方法内置,我们在执行proxy.giveMoney()的同时,实际上是将giveMoney()方法作为参数传进invoke()的参数中去,而此时我们就可以将其他的操作交给invoke,由于所有代理对象在执行时最终都会走invoke方法,所以也为我们的开发节省大量代码

相关文章:

代理模式动态代理

什么是代理模式? 代理模式是开发中常见的一种设计模式,使用代理模式可以很好的对程序进行横向扩展。代理,顾名思义就是一个真实对象会存在一个代理对象,并且代理对象可以替真实对象完成相应操作,外部通过代理对象来访…...

Mysql之二进制日志

目录 二进制日志 12-37 二进制日志格式 基于行的二进制日志 基于语句的二进制日志 混合格式二进制日志 复制日志 12-42 故障安全 (Crash-Safe) 复制 多源复制 二进制日志 12-37 二进制日志: • 包含数据和模式更改及其时间戳 – 基于语句 或 基于行 的日志…...

kail工具的使用--- cewl

1.介绍 Cewl是一款采用Ruby开发的应用程序,可以给他的爬虫指定URL地址和爬取深度,还可以添加外部链接,接下来Cewl会给你返回一个字典文件,你可以把字典用到类似John the Ripper这样的密码破解工具中。 2.使用 输入以下命令之后…...

【蓝桥杯集训1】前缀和专题(2 / 5)

目录 前缀和模板 !3956. 截断数组 - 前缀和枚举 前缀和模板 活动 - AcWing import java.util.*;class Main {static int N100010;static int[] anew int[N],snew int[N];public static void main(String[] args){Scanner scnew Scanner(System.in);int nsc.nex…...

基于模块联邦的微前端实现方案

一、 微前端应用案例概述 当前案例中包含三个微应用,分别为 Marketing、Authentication 和 Dashboard Marketing:营销微应用,包含首页组件和价格组件 Authentication:身份验证微应用,包含登录组件 Dashboard&#x…...

【单目标优化算法】食肉植物优化算法(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

ANTLR4入门学习(四)

ANTLR4入门学习(四)一、设计语法1.语法2.ANTLR核心标记3.常见计算机语言模式4.左右递归5.识别常见的语法结构5.1 匹配标识符5.2 匹配数字5.3 匹配字符串常量5.4 匹配注释和空白字符5.5 基础的语法规则5.6 划定词法分析器和语法分析器的界线一、设计语法 …...

Android okhttp3中发送websocket消息,并通过mockwebserver将一个安卓设备模拟成服务器接发消息

websocket 提供了客户端和服务端的长链接&#xff0c;允许客户端和服务端双向发送消息 okhttp 提供了使用websocket 相关接口议。同时为方便单元测试&#xff0c;又提供了mockwebserver可以把一个安卓客户端作为服务端接受消息。 websocket使用 权限 <uses-permission an…...

MySQL系统变量和自定义变量

1 系统变量1.1 查看系统变量可以使用以下命令查看 MySQL 中所有的全局变量信息。SHOW GLOBAL VARIABLES; MySQL 中的系统变量以两个“”开头。global 仅仅用于标记全局变量&#xff1b;session 仅仅用于标记会话变量&#xff1b;首先标记会话变量&#xff0c;如果会话变量不存在…...

基于Python来爬取某音动态壁纸,桌面更香了!

至于小伙伴们想要这个封图&#xff0c;我也没有。不过继续带来一波靓丽壁纸&#xff0c;而且是动态的&#xff0c;我的桌面壁纸又换了&#xff1a;每天换着花样欣赏一波波动态壁纸桌面立刻拥有了高颜值&#xff0c;简直跟刷美女短视频一样啊。对的&#xff0c;这些动态壁纸就是…...

[数据库]表的约束

●&#x1f9d1;个人主页:你帅你先说. ●&#x1f4c3;欢迎点赞&#x1f44d;关注&#x1f4a1;收藏&#x1f496; ●&#x1f4d6;既选择了远方&#xff0c;便只顾风雨兼程。 ●&#x1f91f;欢迎大家有问题随时私信我&#xff01; ●&#x1f9d0;版权&#xff1a;本文由[你帅…...

VisualGDB 5.6R9 FOR WINDOWS

Go cross-platform with comfort VisualGDB 是 Visual Studio 的一个非常强大的扩展&#xff0c;它允许您调试或调试嵌入式系统。这个程序有一个非常有吸引力的用户界面&#xff0c;它有许多调试或调试代码的功能。VisualGDB 还有一个向导可以帮助您调试程序&#xff0c;为您提…...

Yolov8的多目标跟踪实现

Yolov8_tracking 2023年2月&#xff0c;Yolov5发展到yolov8&#xff0c;这世界变得真快哦。Yolov8由ultralytics公司发布&#xff0c;yolov6-美团&#xff0c;yolov7-Alexey Bochkovskiy和Chien-Yao Wang&#xff0c;其各有高招&#xff0c;对yolov5均有提升。mikel-brostrom在…...

28--Django-后端开发-drf之自定义全局异常、接口文档生成以及三大认证源码分析

一、django请求的整个生命周期 旅程: drf处于的位置:路由匹配成功,进视图类之前 1、包装了新的request 2、处理了编码(urlencoded,formdata,json) 3、三大认证 4、进了视图类(GenericAPIView+ListModelMixin) 进行了过滤和排序去模型中取数据分页序列化返回5、处理了…...

【MyBatis】动态SQL

9、动态SQL Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能&#xff0c;它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。 9.1、if if标签可通过test属性的表达式进行判断&#xff0c;若表达式的结果为true&#xff0c;则标签中的内容会执行&…...

LeetCode(剑指offer) Day1

1.用两个栈实现一个队列。队列的声明如下&#xff0c;请实现它的两个函数 appendTail 和 deleteHead &#xff0c;分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素&#xff0c;deleteHead 操作返回 -1 ) 解题过程记录&#xff1a;本题就是用两个栈&…...

1、MyBatis框架——JDBC代码回顾与分析、lombok插件的安装与使用

目录 一、JDBC基本操作步骤 二、JDBC代码 三、lombok插件的安装与使用 1、lombok插件的安装 2、lombok常用注解 Data Getter Setter ToString AllArgsConstructor NoArgsConstructor 3、lombok的使用 四、JDBC代码分析 一、JDBC基本操作步骤 1、导包mysql-connect…...

笔记-GPS设备定位方式

1. 背景 最近接触到的GPS设备有点多&#xff0c;逐渐明白大家定位的机理&#xff0c;也结合网上的文章《GPS、WiFi、基站、AGPS几种定位原理介绍与区别》 来做一个简单的总结。 2. 基于GPS定位 这是最基本的定位能力&#xff0c;它主要就是寻找卫星&#xff0c;利用光传播速度…...

2023秋招携程SRE算法岗面试经验分享

本专栏分享 计算机小伙伴秋招春招找工作的面试经验和面试的详情知识点 专栏首页:秋招算法类面经分享 主要分享计算机算法类在面试互联网公司时候一些真实的经验 面试code学习参考请看:...

4.9 内部类

文章目录1.内部类概述2.特点3.练习 : 内部类入门案例4.成员内部类4.1 练习 : 被private修饰4.2 练习 : 被static修饰5.局部内部类6.匿名内部类1.内部类概述 如果一个类存在的意义就是为指定的另一个类&#xff0c;可以把这个类放入另一个类的内部。 就是把类定义在类的内部的情…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

Linux 下 DMA 内存映射浅析

序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存&#xff0c;但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程&#xff0c;可以参考这篇文章&#xff0c;我觉得写的非常…...