23模式--代理模式
本篇主要聊一些23中模型中的代理模式:
看一下百度百科的解释:
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式其实有点像是:合作方—经纪人—明星这样关系。
合作方如果想要找明星合作,首先要找到经纪人,具体的谈判合同的事情,先和经纪人进行协商,最后达成合作。
其实代理模式有很多不同的形式,主要有三种:静态代理,动态代理(JDK代理,接口代理),Cglib代理。
一般的组成有:
- 抽象角色:通过接口或抽象类生命真实角色实现的业务方法。
- 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
- 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
静态代理
静态代理在使用时,需要定义接口或者抽象类,也就是被代理对象(明星)与代理对象(经纪人)需要实现相同的接口或者是继承相同的父类。
现在进行代码演示:
-
接口
public interface BusinessInfa { // 签约方法void signContract();} -
被代理类
public class Star implements BusinessInfa {@Overridepublic void signContract() {System.out.println("我是大明星,我同意这份合同了");} } -
代理人
public class Agent implements BusinessInfa{ // 代理谁Star star;public Agent(Star star) {this.star = star;}@Overridepublic void signContract() { // 先联系明星经纪人System.out.println("你好,你找我家明星合作,可以和我谈"); // 谈合同不是简单就可以签约的,肯定要涉及道各种拉扯,合同条款以及费用System.out.println("和经纪人一起疯狂的如果老太太菜市场砍价一般,深入几天各种约各种谈"); // 最后同意了合同this.star.signContract(); // 就算合约签了,具体后面合作中的事情System.out.println("具体合作后现场一些细节,比如我家大明星,剧本改下台词超过十个字了,记不住台词");} } -
客户端调用代理人
public class client {public static void main(String[] args) {// 需要找大明星的联系方式没有,去找大明星公开的经纪人联系System.out.println("我是合作方,需要联系大明星,没办法只能先联系经纪人");BusinessInfa businessInfa=new Agent(new Star());businessInfa.signContract();}}
然后看一下结果:

现在看一下静态代理的优缺点
- 优点: 在不修改目标的对象功能的前提下,通过代理对象对目标公共进行扩展,例子中不会对明星签约的行动进行修改,但是具体谈判细节,以及合作后的出现事故等投通过经纪人进行谈判,毕竟明星给了经纪人钱的。
- 缺点:代理对象需要与目标的对象实现一样的接口,所以会有很多代理类,一旦接口增量了方法,目标对象和代理对象都要维护。也就是比如合作定义的行为,如果增加了明星和经纪人都需要增加行为。
静态代理其实是最方便理解代理这个原理的,而其它无论如何变化,都不能离开这个原理。
动态代理:jdk代理
动态代理类,是位于Java.lang.reflect包下类别的Interface InvocationHandler。其实也是通过反射实现的,所以代理对象不需要实现接口,但是目标对象要实现接口,否则不能用动态代理。而这是利用JDK的API实现的动态代理是在内存中构建代理对象的。
动态代理也被称之为JDK代理,接口代理。
还是老规矩直接用代码演示:
-
被代理类接口
//商务接口 毕竟经纪人代理明星的业务,也是要统一一下什么业务能代理 public interface BusinessInfa { // 签约方法void signContract();void breakContract();} -
被代理类:
public class Agent {// 代理谁Object target;public Agent(Object target) {this.target = target;}// 动态创建不同的代理对象public Object getProxyObject(){Object object=Proxy.newProxyInstance(this.target.getClass().getClassLoader(),this.target.getClass().getInterfaces(),new myInvocationHandler());return object;}class myInvocationHandler implements InvocationHandler{@Override // proxy 在其上调用方法的代理实例 method被代理的方法 代理方法中的参数argspublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 对第一个参数好奇是什么System.out.println("======================================="); // System.out.println(proxy); 这样打印会报错 不过可以看出第一个参数应该是代理对象 一般的时候没有什么用System.out.println(proxy.getClass());System.out.println("=======================================");// 因为要运行的方法没有返回值,所以不接受数据,通过return返回了 同时这里也是可以根据反射判断不同的方法,然后加入不同的逻辑if(method.getName()=="signContract" || method.getName().equals("signContract")){System.out.println("你好,你找我家明星合作,可以和我谈");method.invoke(target,args);System.out.println("后期出现事情,你们必须改,因为我家明星最漂亮,哪怕是她的错你们会原谅的。");// 这里可以返回所代理的类要运行的方法,不过因为我没有返回值,所以直接返回空return null;}else if (method.getName()=="breakContract" || method.getName().equals("breakContract")){System.out.println("你好,你们的错误");method.invoke(target,args);System.out.println("可恶的合作方,不理你们了");// 这里可以返回所代理的类要运行的方法,不过因为我没有返回值,所以直接返回空return null;}return null;}} } -
调用类
public class client {public static void main(String[] args) {// 需要找大明星的联系方式没有,去找大明星公开的经纪人联系System.out.println("我是合作方,需要联系大明星,没办法只能先联系经纪人");Agent agent= new Agent(new Star());BusinessInfa businessInfa = (BusinessInfa) agent.getProxyObject();businessInfa.signContract();System.out.println("*********************************************");businessInfa.breakContract();} }然后看一下输出结果:

可以看下类关系图:

jdk代理的优缺点:
- 优点 :JDK原声动态代理时java原声支持的、不需要任何外部依赖。而且可以动态生成代理类,方不需要像静态代理哪里代理类因为接口变化而不停的调整。
- 缺点:但是它只能基于接口进行代理,也就是被代理的对象也需要有一个接口,不然无法使用jdk代理,同时因为它已经继承了proxy了,java不支持多继承。
动态代理:Cglib代理
无论静态代理还是上面提到的JDK动态代理都需要实现一个接口,但是有时候对象只是一个单独的对象,并没有实现任何的接口,这个时候就需要使用目标对象的子类来实现。而聊到的Cglib动态代理就算通过这种方式实现代理的。
Cglib代理也叫做子类代理,其是再内存中构建了一个子类对象,从而实现对目标对象功能的扩展。Cglib代理是可以再运行期扩展java类与实现java接口,所以其广泛被需要AOP框架使用,其中就包括spring,通过Cglib实现方法拦截。
因为是内存中动态构建子类,所以Cglib代理类不能为final。同样如果目标对象的方法如果为final或者static,代理也会不对其方法进行代理。
其实AOP中不一定会都选择使用Cglib代理,我们开发中同样是如此选择的:
- 目标对象需要实现接口,那就使用JDK代理。
- 目标对象不需要实现接口,那句使用Cglib代理。
Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类。
需要Jar包
这个有两种情况,
-
如果引入的是Cglib的jar包就需要四个包:
asm.jar asm-commons.jar asm-tree.jar Cglib-*.*.jar(自己选版本)
-
如果使用 cglib-nodep的jar,直接导入这一个就行,因为其打包了cglib所需要的依赖jar包
代码演示
-
被代理的对象,无需实现接口
public class Star {public void signContract() {System.out.println("我是大明星,我同意这份合同了");}public void breakContract() {System.out.println("台词超过三句了,编辑不修改剧本,合作方的错误,毁约了。。。。");} } -
使用Cglib代理的增强代理类
// 经纪人代理 需要实现Cglib代理中接口方法MethodInterceptor public class Agent implements MethodInterceptor {// 代理谁Object target;public Agent(Object target) {this.target = target;}// 动态创建不同的代理对象public Object getProxyObject(){ // 创建一个Cglib包下的工具栏Enhancer enhancer=new Enhancer(); // 设置父类enhancer.setSuperclass(target.getClass()); // 设置回调函数,这个回调本身是自己所以enhancer.setCallback((Callback) this); // 创建子类对象 也就是代理对象return enhancer.create();}@Override // 需要重写这个方法,代理类调用方法的时候会走个方法 // o 代表的this 就算代理增强的对象 Method 被代理对象执行的方法,也就是拦截的方法 objects 方法的参数 methodProxy 用于调用super(非拦截方法);可以根据需要调用多次public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {// 因为要运行的方法没有返回值,所以不接受数据,通过return返回了 同时这里也是可以根据反射判断不同的方法,然后加入不同的逻辑if(method.getName()=="signContract" || method.getName().equals("signContract")){System.out.println("你好,你找我家明星合作,可以和我谈");method.invoke(target,objects);System.out.println("后期出现事情,你们必须改,因为我家明星最漂亮,哪怕是她的错你们会原谅的。");// 这里可以返回所代理的类要运行的方法,不过因为我没有返回值,所以直接返回空return null;}else if (method.getName()=="breakContract" || method.getName().equals("breakContract")){System.out.println("你好,你们的错误");method.invoke(target,objects);System.out.println("可恶的合作方,不理你们了");// 这里可以返回所代理的类要运行的方法,不过因为我没有返回值,所以直接返回空return null;}return null;} } -
调用测试的类
public class client {public static void main(String[] args) {// 需要找大明星的联系方式没有,去找大明星公开的经纪人联系System.out.println("我是合作方,需要联系大明星,没办法只能先联系经纪人");Agent agent= new Agent(new Star());Star star = (Star) agent.getProxyObject();star.signContract();System.out.println("*********************************************");star.breakContract();} }

也没有问题,可以实现动态代理。
补充 其它代理
这个只是写了几个代理的名字,也不是全部。
- 防火墙代理: 内网通过代理穿透防火墙,对公网进行访问。
- 缓存代理: 如果获取网络资源有些从缓存中回去资源,如果没有了再从其它地方获取资源。
- 远程代理:远程代理通过网络和真正的远程对象沟通信息。常见的翻墙梯子就算这个逻辑。
- 同步代理: 主要使用在多线程编程中,完成多线程间同步工作
相关文章:
23模式--代理模式
本篇主要聊一些23中模型中的代理模式: 看一下百度百科的解释: 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目…...
【Linux】信号的产生、保存、捕捉处理 (四种信号产生、核心存储、用户态与内核态、信号集及其操作函数)
文章目录1、什么是信号?2、信号的产生2.1 通过键盘产生信号2.2 通过系统调用产生信号2.3 硬件异常产生的信号2.4 由软件条件产生的信号2.5 进程的核心转储3、信号的保存4、信号的捕捉4.1 用户态和内核态4.2 用户态到内核态的切换4.3 信号捕捉过程5、信号集操作函数以…...
redis经典五种数据类型及底层实现
目录一、Redis源代码的核心部分1.redis源码在哪里2.src源码包下面该如何看?二、我们平时说redis是字典数据库KV键值对到底是什么1.6大类型说明(粗分)2.6大类型说明3.上帝视角4.Redis定义了redisObject结构体4.1 C语言struct结构体语法简介4.2 字典、KV是什么4.3 red…...
三十而立却被裁,打工人要如何应对职场危机?
又到金三银四就业季,对于部分职场人来说,年龄成为了他们找工作的最大限制。 因为绝大部分企业招聘中层干部以下岗位的时候,都会要求年龄不超过35周岁,再加上每年千万毕业生涌入社会,竞争程度相当激烈,这就导…...
java面试-java基础
char 变量能不能存贮一个中文汉字?为什么? char 变量可以存贮一个汉字,因为 Java 中使用的默认编码是 Unicode ,一个 char 类型占 2 个字节(16 bit),一个汉字是2个字节,所以放一个中…...
Kafka 消息不丢失
Kafka 消息不丢失生产者丢失消费者丢失不丢失配置Kafka 保证消息不丢失:只对已提交的消息 (committed message) 做有限度的持久化保证 已提交的消息:当 n 个 Broker 成功接收到该消息并写入到日志文件后,就告诉生产者该消息已成功提交有限度…...
ASEMI高压MOS管10N65参数,10N65规格,10N65封装
编辑-Z ASEMI高压MOS管10N65参数: 型号:10N65 漏极-源极电压(VDS):650V 栅源电压(VGS):30V 漏极电流(ID):10A 功耗(PDÿ…...
LeetCode-416. 分割等和子集
目录题目分析回溯法动态规划动态规划(压缩)题目来源 416. 分割等和子集 题目分析 这道题目是要找是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 那么只要找到集合里能够出现 sum / 2 的子集总和,就算是可以分割成两个相同元素和子集了…...
2021年 第12届 蓝桥杯 Java B组 省赛真题详解及小结【第2场省赛 2021.05.09】
一、试题A:求余(本题总分:5 分) 得:5分 本题总分:5 分 【问题描述】 在 C/C/Java/Python 等语言中,使用 % 表示求余,请问 2021%20 的值是多少? 【答案提交】 这是一道结果…...
elasticSearch写入原理
elasticSearch写入原理 最近学习完了es相关的课程整理除了es的核心内容,学习这东西知其然知其所以然,自己按照自己的理解整理了es相关的面试题。先热个身,整理一下es的写入原理,有不对的地方请大家指正。 这些原理的东西我觉得还是…...
第十四届蓝桥杯模拟赛(第三期)Python
1 进制转换 问题描述 请找到一个大于 2022 的最小数,这个数转换成十六进制之后,所有的数位(不含前导 0)都为字母(A 到 F)。 请将这个数的十进制形式作为答案提交。 答案:2730 def ch…...
Pytorch模型参数的保存和加载
目录 一、前言 二、参数保存 三、参数的加载 四、保存和加载整个模型 五、总结 一、前言 在模型训练完成后,我们需要保存模型参数值用于后续的测试过程。由于保存整个模型将耗费大量的存储,故推荐的做法是只保存参数,使用时只需在建好模…...
面试热点题:回溯算法之组合 组合与组合总和 III
什么是回溯算法? 回溯算法也可以叫回溯搜索算法,回溯是递归的"副产品",回溯的本质是穷举,然后选出我们需要的数据,回溯本身不是特别高效的算法,但我们可以通过"剪枝"来优化它。 理解回溯算法 回溯…...
java面试-jvm
JVM JVM 是 java 虚拟机,简单来说就是能执行标准 java 字节码的虚拟计算机 JVM 是如何工作的 首先程序在执行之前先要把 Java 代码(.java)转换成字节码(.class),JVM 通过类加载器(ClassLoade…...
vscode下载与使用
1.vscode下载 官网下载地址:Download Visual Studio Code - Mac, Linux, Windows下载太慢,推荐文章:解决VsCode下载慢问题_vscode下载太慢_迷小圈的博客-CSDN博客下载太慢,推荐下载链接:https://vscode.cdn.azure.cn/s…...
人员摔倒识别预警算法 opencv
人员摔倒识别预警算法通过opencv网络模型技术,人员摔倒识别预警算法能够智能检测现场画面中人员有没有摔倒,无需人为干预可以立刻抓拍告警。OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉处理开源软件库&…...
华为OD机试题 - 火星文计算(JavaScript)| 机考必刷
更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 华为OD机试题 最近更新的博客使用说明本篇题解:火星文计算题目输入输出示例一输入输出说明Code解题思路版权说明…...
AI人工智能 - 初探
1.应用场景 主要用于了解和系统学习AI,从而可以在工作生活中利用AI做一些事。 2.学习/操作 1.文档阅读 下面的内容来自于与chatGPT的对话 2.整理输出 介绍AI 人工智能(Artificial Intelligence,简称AI)是计算机科学中的一个分支&…...
Spring-AOP工作流程
Spring-AOP工作流程 3,AOP工作流程 3.1 AOP工作流程 由于AOP是基于Spring容器管理的bean做的增强,所以整个工作过程需要从Spring加载bean说起: 流程1:Spring容器启动 容器启动就需要去加载bean,哪些类需要被加载呢?需要被增强的类,如:B…...
C51---串口发送指令,控制LED灯亮灭
1.Code: #include "reg52.h" #include "intrins.h" sfr AUXR 0x8E; sbit D5 P3^7; void UartInit(void) //9600bps11.0592MHz { //PCON & 0x7F; //波特率不倍速 AUXR 0x01; SCON 0x50; //8位数据,可变波…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...
