代理模式概述
1.代理模式概述
学习内容
1)概述
为什么要有 “代理” ?
- 生活中就有很多例子,比如委托业务,黄牛(票贩子)等等
- 代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,这才是“代理”存在的原因。
- 例如要租房子,房产中介可以在我们住房前代理我们找房子。中介就是代理,而自己就是被代理了。
在代码设计中,代理模式作用主要就是让 “被代理对象” 的某个方法执行之前或者执行之后加入其他增强逻辑。
前增强 : 例如获取当前时间被代理对象调用方法后增强 : 例如获取当前时间计算方法执行的时间
2)代理的前提条件 : 掌握 !
- 抽象角色 :声明功能
- 代理角色 :实现抽象功能 , 完成代理逻辑
- 被代理角色 :实现抽象功能
意味着被代理角色和代理角色有着共同的父类型(既抽象角色) , 例如我要租房子, 我只能找房产中介, 不能找票贩子
-
代理模式存在两种实现方式:
- 静态代理
- 动态代理
知识小结
-
请说出代码中代理模式的作用?
代理角色对 被代理就角色某个方法执行的前或者后进行 功能增强
-
请说出代理模式中的三个角色?
抽象角色 代理角色 被代理角色
==============================================================================================================
1.1 静态代理
学习目标
- 能够写出静态代理模式代码
内容讲解
-
静态代理是由程序员创建 或 工具生成代理类的源码,再编译代理类。
在程序运行前就已经存在代理类的字节码文件,代理类和被代理类的关系在运行前就确定了。
简单理解 : 在程序运行之前 , 代理类就存在了,这就是静态代理 ; 动态代理是程序运行时动态生成代理类
-
静态代理实现的步骤 :
- 存在一个抽象角色
- 定义被代理角色
- 定义代理,增强被代理角色的功能
案例实践 :
- 以现实中经纪人代理明星
已知存在接口:
// 1.抽象角色
interface Star {// 真人秀方法double liveShow(double money);void sleep();
}
定义被代理类:
- 定义王宝强类,实现Star方法
// - 定义被代理角色(宝强)
class BaoQiang implements Star {@Overridepublic double liveShow(double money) {System.out.println("宝强参加了一个真人秀活动赚了" + money + "钱");return money;}@Overridepublic void sleep() {System.out.println("宝强累了 , 睡觉...");}
}
定义代理类:
- 定义宋喆经纪人类
// - 定义代理角色(宋喆),增强被代理角色的功能
class SongZhe implements Star {private BaoQiang baoQiang;public SongZhe(BaoQiang baoQiang) {this.baoQiang = baoQiang;}@Overridepublic double liveShow(double money) {// 前增强System.out.println("宋喆帮宝强拉了一个真人秀的活动,获取佣金" + money * 0.8 + "元");// 被代理角色的功能double result = baoQiang.liveShow(money * 0.2);// 后增强System.out.println("宋喆帮宝强把赚的钱存了起来...");return result;}@Overridepublic void sleep() {// 前增强System.out.println("宋喆帮宝强定了一家五星级大酒店");baoQiang.sleep();// 后增强System.out.println("宋喆帮宝强退房...");}
}
定义测试类进行测试
/*静态代理实现的步骤 :- 存在一个抽象角色- 定义被代理角色(宝强)- 定义代理角色(宋喆),增强被代理角色的功能*/
public class StaticAgentDemo {public static void main(String[] args) {// 创建被代理角色 , 没有任何增强BaoQiang baoQiang = new BaoQiang();double result = baoQiang.liveShow(1000);System.out.println(result);baoQiang.sleep();System.out.println("===========================");// 创建代码角色对象 , 可以对被代理角色功能做前后增强SongZhe songZhe = new SongZhe(baoQiang);double result2 = songZhe.liveShow(1000);System.out.println(result2);songZhe.sleep();}
}
关系图 :
宋喆和宝强都有共同的父类型。他们的业务方法都是一样。
静态代理和装饰模式的对比 :
BufferedRead(FileRead)
1 装饰设计模式是功能扩展功能,在原有的功能基础之上增加了新的功能
2 而代理主要对功能的前后做了增强
知识小结
-
请问什么叫做静态代理?
代码执行前,已经确定了代理的代码逻辑。
2. 动态代理
学习目标
- 能够知道什么是动态代理
- 能够熟悉动态代理相关API
- 能够熟悉动态代理代码执行流程
内容讲解
1)概述
在实际开发过程中往往我们自己不会去创建代理类而是通过JDK提供的Proxy
类在程序运行时,运用反射机制动态创建而成
这就是我们所谓的动态代理。
与静态代理之间的区别,在于不用自己写代理类
虽然我们不需要自己定义代理类创建代理对象
但是我们要定义对被代理对象直接访问方法的拦截,原因就是对拦截的方法做增强。
动态代理技术在框架中使用居多,例如:很快要学到的数据库框架MyBatis框架等一些主流框架技术(Spring,SpringMVC)中都使用了动态代理技术。
2)API学习
Proxy类
java.lang.reflect.Proxy
类提供了用于创建动态代理类和对象的静态方法
它还是由这些方法创建的所有动态代理类的超类(代理类的父类是Proxy)。
public static Object newProxyInstance (ClassLoader loader, Class<?>[] interfaces, InvocationHandler h ) 获取代理对象的方法 - 返回值:该方法返回就是动态生成的代理对象
- 参数列表说明:1. ClassLoader loader - 定义代理类的类加载器2. Class<?>[] interfaces - 代理类要实现的接口列表,要求与被代理类的接口一样。3. InvocationHandler h - 就是具体实现代理逻辑的接口
InvocationHandler接口
源码 :
interface InvocationHandler{public Object invoke(Object proxy, Method method, Object[] args); //代理逻辑
}
java.lang.reflect.InvocationHandler
是代理对象的实际处理代理逻辑的接口,具体代理实现逻辑在其 invoke 方法中。所有代理对象调用的方法,执行是都会经过invoke。因此如果要对某个方法进行代理增强,就可以在这个invoke方法中进行定义。
方法说明如下:
public Object invoke(Object proxy, Method method, Object[] args);1. 返回值:方法被代理后执行的结果。
2. 参数列表:1. proxy - 就是代理对象2. method - 代理对象调用的方法3. args - 代理对象调用方法传入参数值的对象数组.
3)代码实践
将经纪人代理明星的案例使用动态代理实现
- 把父接口定义
- 定义被代理类:宝强
- 动态生成代理类
- 定义代理逻辑
package com.itheima.dynamicproxy_demo;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 测试类
/*1 Proxy类 :public static Object newProxyInstance (ClassLoader loader,Class<?>[] interfaces,InvocationHandler h ) 获取代理对象的方法- 返回值:该方法返回就是动态生成的代理对象- 参数列表说明:1. ClassLoader loader - 定义代理类的类加载器2. Class<?>[] interfaces - 代理类要实现的接口列表,要求与被代理类的接口一样。3. InvocationHandler h - 就是具体实现代理逻辑的接口2 InvocationHandler接口public Object invoke(Object proxy, Method method, Object[] args);1. 返回值:方法被代理后执行的结果。2. 参数列表:1. proxy - 就是代理对象2. method - 代理对象调用的方法3. args - 代理对象调用方法传入参数值的对象数组.*/
public class DynamicProxyDemo {public static void main(String[] args) {// Proxy.newProxyInstance(被代理角色的类加载器 , 被代理角色实现的所有接口 , 处理器);// 被代理角色的类加载器ClassLoader classLoader = BaoQiang.class.getClassLoader();// 被代理角色实现的所有接口Class<?>[] interfaces = BaoQiang.class.getInterfaces();// 创建被代理角色对象BaoQiang baoQiang = new BaoQiang();// 代理角色 , 动态生成Star songZhe = (Star) Proxy.newProxyInstance(classLoader, interfaces, new MyInvocationHandler(baoQiang));// 代理角色调用liveShow方法songZhe.liveShow(1000);songZhe.sleep();}
}// 定义InvocationHandler接口的实现类
class MyInvocationHandler implements InvocationHandler {private BaoQiang baoQiang;public MyInvocationHandler(BaoQiang baoQiang) {this.baoQiang = baoQiang;}// invoke什么时候会执行????// 代理对象调用功能 , 就会触发invoke方法// 此方法对被代理角色的功能做增强// method : 代理对象调用功能就会触发invoke方法 , invoke方法中的method代表的就是调用的方法对象@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (method.getName().equals("liveShow")) {// 代理角色对象调用liveShow方法 , 此位置会拦截// 前增强System.out.println("宋喆帮宝强拉了一个真人秀的活动,获取佣金" + (double) args[0] * 0.8 + "元");Object result = method.invoke(baoQiang, (double) args[0] * 0.2);// 后增强System.out.println("宋喆帮宝强把赚的钱存了起来...");return result;} else if (method.getName().equals("sleep")) {// 代理角色对象调用sleep方法 , 此位置会拦截method.invoke(baoQiang);} else {// 除了liveShow和sleep方法 , 会执行else代码块中的内容}return null;}
}// 1 抽象角色
interface Star {double liveShow(double money);void sleep();
}// 2 定义被代理角色(宝强)
class BaoQiang implements Star {@Overridepublic double liveShow(double money) {System.out.println("宝强参加了一个真人秀活动赚了" + money + "钱");return money;}@Overridepublic void sleep() {System.out.println("宝强累了 , 睡觉...");}
}
动态代理调用流程:
小结
-
什么是动态代理?
在代码执行前,没有代理类,代理类是在程序运行的时候动态生成.Proxy.newProxyInstance
-
动态代理有什么好处?
动态代理可以为 “被代理对象” 的所有接口的所有方法做代理,动态代理可以在不改变方法源码的情况下,实现对方法功能的增强。 -
动态代理相关的API有哪些?
Proxypublic static Object newProxyInstance(类加载器,接口列表,调用处理器)类加载器 = 被代理对象.getClass().getClassLoader();接口列表 = 被代理对象.getClass().getInterfaces();调用处理器 = new InvocationHandler(){ 实现 invoke 方法 };InvocationHandlerpublic Object invoke(代理对象,方法对象,方法的实参类别) 该方法执行时机是,代理对象调用方法时触发执行
-
动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。
-
缺点 :只能针对接口的实现类做代理对象,普通类是不能做代理对象的。
后面框架学习的时候会接触到CGLib(Code Genneration Library ): 可以实现对类的代理
相关文章:

代理模式概述
1.代理模式概述 学习内容 1)概述 为什么要有 “代理” ? 生活中就有很多例子,比如委托业务,黄牛(票贩子)等等代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这…...

最新AI系统ChatGPT网站程序源码+搭建教程/公众号/H5端/安装配置教程/完整知识库
1、前言 SparkAi系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美,可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。 那么如何搭建部署AI创作ChatGPT?小编这里写一个详细图文教程吧!…...
前端Flex布局
day06-Flex布局 目标:熟练使用 Flex 完成结构化布局 01-标准流 标准流也叫文档流,指的是标签在页面中默认的排布规则,例如:块元素独占一行,行内元素可以一行显示多个。 [外链图片转存失败,源站可能有防盗链机制,建议…...
文盘Rust -- Mutex解决并发写文件乱序问题 | 京东云技术团队
在实际开发过程中,我们可能会遇到并发写文件的场景,如果处理不当很可能出现文件内容乱序问题。下面我们通过一个示例程序描述这一过程并给出解决该问题的方法。 use std::{fs::{self, File, OpenOptions},io::{Write},sync::Arc,time::{SystemTime, UNI…...

数据结构算法--2 冒泡排序,选择排序,插入排序
基础排序算法 冒泡排序 思想就是将相邻元素两两比较,当一个元素大于右侧相邻元素时,交换他们的位置,小于右侧元素时,位置不变,最终序列中的最大元素,像气泡一样,到了最右侧。 这时冒泡排序第一…...
秋招面经——快手
Mysql mysql事务 共享锁与排他锁 共享锁:允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。(读都允许读,但我在读不允许你去改) 排他锁:允许一个事务去读一行,阻止其他事务获得相同…...

【STM32RT-Thread零基础入门】 2. 新建RT-Thread项目
硬件:STM32F103ZET6、ST-LINK、usb转串口工具 文章目录 前言一、新建RT-Thread项目二、项目结构三、构建项目四、下载程序(调试器下载)五、终端交互总结 前言 RT-Thread的全称是Real Time Thread,顾名思义,它是一个嵌…...

别人直播的时候怎么录屏?分享一些录屏方法
随着互联网的快速发展,直播已经成为人们日常生活中不可或缺的一部分。但是,有时候我们可能会错过某些重要的直播内容,这时候就需要录屏来保存和观看。那么,如何录屏别人的直播呢?本文将分享一些录屏方法和技巧&#…...
React Native 在高IOS版本下无法显示图片的问题处理
图片在低ios版本下可以看到图片,在高版本ios下显示不了图片 直接上解决方法 找文件 /node_modules/react-native/Libraries/Image/RCTUIImageViewAnimated.m 修改源码 原代码 if (_currentFrame) {layer.contentsScale self.animatedImageScale;layer.contents…...

SSH远程连接MacOS catalina并进行终端颜色配置
一、开关SSH服务 在虚拟机上安装了MacOS catalina,想要使用SSH远程进行连接,但是使用“系统偏好设置”/“共享”/“远程登录”开关进行打开,却一直是正在启动“远程登录”: 难道是catalina有BUG?不过还是有方法的&…...
用JSON.toJSONString转JSON时,属性的值为null时,输出的JSON里没有该属性
1、问题 用JSON.toJSONString转JSON时,当属性值为null的话,转出来的JSON里没有了值为null的属性,属性丢失了 2、原因 用fastjson将java对象转json字符串时会默认去除空字段 2、解决办法 在JSON.toJSONString方法加上SerializerFeature这一…...

Java版企业电子招标采购系统源码—企业战略布局下的采购寻源tbms
项目说明 随着公司的快速发展,企业人员和经营规模不断壮大,公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境,最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范,以…...

轻拍牛头(约数)
题意:求ai在n个数中,ai可以整除的数有多少个,不包括ai自己。 分析:暴力写需要n^2的时间复杂度,此时想一下预处理每个数的倍数,约数和倍数是有关系的,把每个数的倍数都加上1. #include<bits…...

Vc - Qt - 绘制窗口背景色
要在Qt中绘制一个背景颜色,你可以使用Qt的绘图功能来完成。下面是一种简单的方法: 步骤1:在你想要绘制背景颜色的QWidget(例如QMainWindow或QDialog)的派生类中,重写 它的paintEvent函数。步骤2:…...
js和cocos creator学习笔记
1.Javascript有哪些数据类型?举例两个最常见的内置对象数据类型? 常用的数据类型:Number,String,Boolean,Null,Undefined,Object 常见内置对象:Array,Function2.下面代码输出内容是什么? let a []; a[10] 10; console.log(a.length); console.log(a[0]); a[200] undefi…...
Ceph分布式存储系统
Ceph 是一个开源的分布式存储系统,旨在提供高性能、高可靠性和可扩展性的存储解决方案。它被设计用于管理大规模的数据,可以轻松地扩展到数千台服务器和多个存储节点,适用于私有云、公有云、虚拟化环境等多种场景。 Ceph 的主要特点和组件包…...
阿里云SMS,APi接口返回错误码
API错误码 更新时间:2023-06-29 16:33提交缺陷 产品详情 相关技术圈 我的收藏 调用API接口失败时,会返回错误码。本文档为您提供API接口错误码列表,请根据错误码和对应错误信息排查问题。 错误码(Code) 错误信息…...

Floyd算法
正如我们所知道的,Floyd算法用于求最短路径。Floyd算法可以说是Warshall算法的扩展,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3)。 Floyd算法的基本思想如下:从任意节点A到任意节点B的最短路径不外乎2种可能ÿ…...
SpringBoot究竟应该如何学习?
如果你有Spring的基础,学习Spring Boot就很简单了。 首先要知道Spring Boot是建立在Spring框架之上的,它旨在简化和加速Java应用程序的开发过程。 Spring Boot的目标是简化Spring应用程序的配置和开发,通过提供自动配置、快速开发和零配置的…...

为什么很多人认为ChatGPT最好的替代工具是Claude?
ChatGPT引领着生成式AI聊天机器人领域,但Claude AI看起来是一个有力的竞争者。 前段时间,ChatGPT的强劲竞争对手Claude2面世。当时很多人认为它可能会取代ChatGPT,在体验过一段时间之后,深以为然。原因如下: 更强大的…...

深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...