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

3_代理模式(动态代理JDK原生和CGLib)

一.代理模式

1.概念

代理模式(Proxy Pattern )是指为其他对象提供一种代理,以控制对这个对象的访问,属于结构型模式。

在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

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

2.代理模式三种角色

2.1 抽象角色( Subject ): 抽象主题类的主要职责是声明真实主题与代理的共同接口方法,该类可以是接口也可以是抽象类

2.2 真实角色(RealSubiect ): 该类也被称为被代理类,该类定义了代理所表示的真实对象,是负责执行系统真正的逻辑业务对象:

2.3 代理角色 ( Proxy): 也被称为代理类,其内部持有 RealSubiect 的用,因此具备完全的对RealSubiect 的代理权。客户端调用代理对象的方法,同时也调用被代理对象的方法,但是会在代理对象前后增加一些处理代码

二.代理模式的通用写法

2.1 创建一个抽象角色:用于代理和真实对象共同接口方法。

public interface ISubject {void request();
}

2.2 创建一个真实角色:用于执行真正的业务逻辑处理。

public class RealSubject implements ISubject {public void request() {System.out.println("real service is called.");}
}

2.3 创建一个代理角色:调用真实业务逻辑时候前后自己处理逻辑代码。

public class Proxy implements ISubject {//1.获取真实对象封装处理private ISubject subject;public Proxy(ISubject subject){this.subject = subject;}//2.调用真实对象业务逻辑,前后加一些自己逻辑增强处理。public void request() {before();subject.request();after();}//3.前后增加逻辑处理public void before(){System.out.println("called before request().");}public void after(){System.out.println("called after request().");}
}

2.4 测试功能

public class Client {public static void main(String[] args) {//创建代理对象并绑定一个真实对象Proxy proxy = new Proxy(new RealSubject());//执行代理对象功能调用proxy.request();}
}//--结果处理------------
called before request().
real service is called.
called after request().

三.静态代理到动态代理

1.抽取角色:定义一个接口用于真实和代理对象共同的接口方法
//定义人的接口,相亲接口方法
public interface IPerson {void findLove();
}
2.真是角色:创建一个真正的人的对象并实现相亲接口方法具体逻辑
//定义一个张三人对象并提出相亲的要求
public class ZhangSan implements IPerson {public void findLove() {System.out.println("张三:要求相亲女孩长得好看又善良");}
}3.代理角色:创建一个代理张三对象(张三的父亲)代理完成张三的相亲要求。
public class ZhangLaosan implements IPerson {//---静态代理------------------------//1.创建获取静态代理对象处理【只能接受张三这个人,其他人不能接受】private ZhangSan zhangsan;public ZhangLaosan(ZhangSan zhangsan) {this.zhangsan = zhangsan;}//2.完成张三的相亲,并在相亲的前后做一些工作和处理。public void findLove() {System.out.println("张老三开始物色");zhangsan.findLove();System.out.println("开始交往");}//---动态代理------------------------//1.创建获取动态代理对象处理【只要实现抽象角色的接口,任何真实对象都可以接受并执行代理逻辑】private IPerson person;public ZhangLaosan(IPerson person) {this.person = person;}//2.完成张三的相亲,并在相亲的前后做一些工作和处理。public void findLove() {System.out.println("张老三开始物色");person.findLove();System.out.println("开始交往");}
}4.测试代码
public class Test {public static void main(String[] args) {ZhangLaosan zhangLaosan = new ZhangLaosan(new ZhangSan());zhangLaosan.findLove();}
}结果:张老三开始物色张三:要求相亲女孩长得好看又善良开始交往

四. JDKProxy动态代理

1.抽取角色:定义一个接口用于真实和代理对象共同的接口方法
public interface IPerson {void findLove();
}2.真是角色:创建一个真正的人的对象并实现相亲接口方法具体逻辑
//定义一个张三人对象并提出相亲的要求
public class ZhangSan implements IPerson {public void findLove() {System.out.println("张三:要求相亲女孩长得好看又善良");}
}3.代理角色:创建一个代理张三对象(张三的父亲)代理完成张三的相亲要求。
public class JdkMeipo implements InvocationHandler {//1.定义接受真实对象变量private IPerson target;public IPerson getInstance(IPerson target){this.target = target; //真实对象赋值//clazz.getClassLoader():真实对象反射类对象(可以通过目标类的getClassLoader()方法来获取目标类的ClassLoader对象)//clazz.getInterfaces():真实对象接口列表 (Class[]对象,代理类要实现的接口列表。代理类将会实现这些接口,并且可以调用接口中定义的方法)//this:真实对象(InvocationHandler接口的实现类对象,代理类在调用方法时会委托给该InvocationHandler对象来处理)Class<?> clazz =  target.getClass();return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {before();Object result = method.invoke(this.target,args);after();return result;}private void after() {System.out.println("双方同意,开始交往");}private void before() {System.out.println("我是媒婆,已经收集到你的需求,开始物色");}
}4.测试
public class Test {public static void main(String[] args) {JdkMeipo jdkMeipo = new JdkMeipo();//创建一个代理对象IPerson zhangsan = jdkMeipo.getInstance(new Zhangsan());//把真实对象代理处理一个代理张三的对象zhangsan.findLove();}
}结果:张老三开始物色张三:要求相亲女孩长得好看又善良开始交往

五. CGlib动态代理

依赖maven cglib库

cglib
cglib-nodep
2.2

1.定义真实对象类并写真实的业务逻辑处理。
public class Customer {public void findLove(){System.out.println("儿子要求:肤白貌美大长腿");}
}2.定义代理对象
public class CGlibMeipo implements MethodInterceptor {//1.定义接受真实对象处理,返回一个代理对象public Object getInstance(Class<?> clazz) throws Exception{//相当于Proxy,代理的工具类Enhancer enhancer = new Enhancer();enhancer.setSuperclass(clazz);enhancer.setCallback(this);return enhancer.create();}/*o:被代理的对象。即原始对象,也就是目标类的实例。method:要被调用的方法对象。即将要执行的目标方法。objects:方法的参数数组。即目标方法的参数列表。methodProxy:方法的代理对象。通过该对象可以调用目标方法。使用methodProxy.invokeSuper(o, objects)可以触发目标方法的执行。*/public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {before();Object obj = methodProxy.invokeSuper(o,objects);after();return obj;}private void before(){System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");System.out.println("开始物色");}private void after(){System.out.println("OK的话,准备办事");}
}3.测试
public class CglibTest {public static void main(String[] args) {try {System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E://cglib_proxy_classes");//打印代理对象生成的class文件//CGlibMeipo代理对象绑定真实对象并返回代理对象Customer obj = (Customer) new CGlibMeipo().getInstance(Customer.class);//执行代理对象方法并调用真实对象obj.findLove();} catch (Exception e) {e.printStackTrace();}}
}

六. 代理模式的优缺点

代理模式具有以下优点
(1)代理模式能将代理对象与真实被调用目标对象分离

(2)在一定程度上降低了系统的耦合性,扩展性好

(3)可以起到保护目标对象的作用

(4)可以增强目标对象的功能

当然,代理模式也有缺点
( 1)代理模式会造成系统设计中类的数量增加

(2)在客户端和目标对象中增加一个代理对象,会导致请求处理速度变慢.

(3)增加了系统的复杂度

七. JDK Proxy和CGLib比较

JDK是采用读取接口的信息
CGLib覆盖父类方法
目的:都是生成一个新的类,去实现增强代码逻辑的功能
JDK Proxy 对于用户而言,必须要有一个接口实现,目标类相对来说复杂
CGLib 可以代理任意一个普通的类,没有任何要求
CGLib 生成代理逻辑更复杂,效率,调用效率更高,生成一个包含了所有的逻辑的FastClass,不再需要反射调用
JDK Proxy生成代理的逻辑简单,执行效率相对要低,每次都要反射动态调用
CGLib 有个坑,CGLib不能代理final的方法

相关文章:

3_代理模式(动态代理JDK原生和CGLib)

一.代理模式 1.概念 代理模式(Proxy Pattern )是指为其他对象提供一种代理&#xff0c;以控制对这个对象的访问&#xff0c;属于结构型模式。 在某些情况下&#xff0c;一个对象不适合或者不能直接引用另一个对象&#xff0c;而代理对象可以在客户端和目标对象之间起到中介的…...

Linux的权限(1)

目录 操作系统的"外壳"程序 外壳程序是什么&#xff1f; 为什么存在外壳程序&#xff1f; 外壳程序怎么运行操作&#xff1f; 权限 什么是权限&#xff1f; 权限的本质&#xff1f; Linux中的&#xff08;人&#xff09;用户权限&#xff1f; su和su -的区别…...

数据安全保障的具体措施有哪些

随着信息化时代的到来&#xff0c;数据已经成为企业和社会发展的重要资产。然而&#xff0c;数据安全问题也日益突出&#xff0c;如何保障数据的安全性、完整性和可用性成为了亟待解决的问题。以下将详细探讨数据安全保障的各个方面&#xff0c;以期为企业和社会提供更好的数据…...

浅谈标签及应用场景

一、标签的定义 标签是根据业务场景的需求&#xff0c;通过对目标对象&#xff08;包含静态、动态特性&#xff09;&#xff0c;运用抽象、归纳、推理等算法得到的高度精炼的特征标识&#xff0c;用于差异化管理与决策。标签由标签名称和标签值组成&#xff0c;打在目标对象上…...

Linux动态分配IP与正向解析DNS

目录 一、DHCP分配 1. 动态分配 1.1 服务端服务安装 1.2 修改服务端dhcp配置 1.3 修改客户端dhcp&#xff0c;重启查询网卡信息 2. 根据mac固定分配 2.1 修改服务器端dhcp服务配置 2.2 客户端自动获取&#xff0c;查看网卡信息 二、时间同步 1. 手动同步 2. 自动同…...

pyspark 使用udf 进行预测,发现只起了一个计算节点

PySpark UDF 只使用一个计算节点的问题 原因分析 默认的并行度设置 PySpark在执行UDF&#xff08;用户定义函数&#xff09;时&#xff0c;默认可能不会利用所有可用的计算节点。这是因为UDF通常在单个节点上执行&#xff0c;并且如果没有正确设置分区&#xff0c;可能会导致数…...

mysql触发器的简单使用

mysql触发器 触发器是一个特殊的存储过程&#xff0c;在事件delete、insert、update发生时自动执行一条或多条SQL语句&#xff08;执行多条SQL语句需要用begin、end 包裹起来&#xff09; 创建触发器 创建触发器的四大必要条件 唯一的触发器名称触发器关联的表触发器响应的…...

全志T113开发板Qt远程调试

1引言 通常情况下工程师在调试Qt程序时&#xff0c;需要频繁制作镜像烧录到核心板来测试Qt程序是否完善&#xff0c;这样的操作既费时又费力。这时我们可以通过QtCreator设备功能&#xff0c;定义设备后&#xff0c;在x86_64虚拟机上交叉编译qt程序&#xff0c;将程序远程部署到…...

学习使用php、js脚本关闭当前页面窗口的方法

学习使用php、js脚本关闭当前页面窗口的方法 前言方法一&#xff1a;使用JavaScript代码方法二&#xff1a;通过http头文件来实现方法三&#xff1a;使用服务器端脚本来实现 前言 在开发web应用程序时&#xff0c;我们通常需要在不同的网页之间进行导航。通常情况下&#xff0…...

python 人脸检测与人脸识别

安装库文件: pip install dlib face_recognition import dlib import face_recognition import cv2 from PIL import Image, ImageDraw# 判断运行环境 cpu or gpu def check_env():print(dlib.DLIB_USE_CUDA)print(dlib.cuda.get_num_devices())# 判断人脸在图片当中的位置 def…...

RT-Thread: ulog 日志 讲解和使用

说明&#xff1a;记录 RT-Thread: ulog 日志功能和使用流程。 官网资料链接&#xff1a; https://docs.rt-thread.org/#/rt-thread-version/rt-thread-standard/programming-manual/ulog/ulog 1.ulog 简介 日志的定义&#xff1a;日志是将软件运行的状态、过程等信息&#x…...

git ssh key 配置

一、Profile Settings-->SSH Keys 我们点击这里会有详情的文档介绍生成sshkey。 ssh-keygen -t rsa -b 2048 -C "邮箱" --回车... 将生成的id_rsa.pub粘贴到如下保存 git config --global user.name "用户名" git config --global user.email "邮…...

MongoDB聚合:$documents

$documents阶段可以根据输入值返回字面意义的文档。 语法 { $documents: <表达式> }$documents接受可解析为对象数组的任何有效表达式&#xff0c;包括&#xff1a; 系统变量&#xff0c;如 $$NOW 或 $$SEARCH_META $let 表达式 $lookup 表达式作用域中的变量 没有…...

程序员英语 - 英文会议常用句型

相信大部分程序员都会有如下经历&#xff1a; 产品经理&#xff08;BA&#xff09;们在和外系统聊集成方案时或者给用户解决某个问题时发现搞不定了&#xff0c;这个时候就会拉上程序员一起上会参与讨论或者排查问题&#xff0c;但程序员们英文又不好&#xff0c;上了会又听不懂…...

UV贴图和展开初学者指南

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 介绍 这正是本文的主题——UV贴图——登上舞台的时候。大多数 3D 建…...

解密Path环境变量

解密Path环境变量 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;让我们一起深入探讨程序开发中不可或缺的一项关键技术——“path环境变量”。无论…...

git撤销提交到本地的commit

有些时候&#xff0c;当我们提交代码到本地后&#xff0c;突然发现因为某些原因需要撤销提交本地的代码。 就比如我&#xff0c;因为代码写错了分支&#xff0c;已经提交到本地了&#xff0c;而我需要取消&#xff0c;并且还要把代码搞得另外的分支上。 提交前&#xff1a; …...

使用Adobe Acrobat Pro DC给pdf文件填加水印

前言 GPT4的官方售价是每月20美元&#xff0c;很多人并不是天天用GPT&#xff0c;只是偶尔用一下。 如果调用官方的GPT4接口&#xff0c;就可以按使用量付费&#xff0c;用多少付多少&#xff0c;而且没有3个小时内只能提问50条的使用限制。 但是对很多人来说调用接口是比较麻烦…...

解决:Unity : Error while downloading Asset Bundle: Couldn‘t move cache data 问题

目录 问题&#xff1a; 尝试 问题得到解决 我的解释 问题&#xff1a; 最近游戏要上线&#xff0c;发现一个现象&#xff0c;部分机型在启动的时候闪退或者黑屏&#xff0c;概率是5%左右&#xff0c;通过Bugly只有个别机型才有这个现象&#xff0c;其实真实情况比这严重的多…...

SpringBoot默认配置文件

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: 循序渐进学SpringBoot ✨特色专栏: MySQL学习 🥭本文内容:SpringBoot默认配置文件 📚个人知识库: Leo知识库,欢迎大家访问 1.前言☕…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

代码规范和架构【立芯理论一】(2025.06.08)

1、代码规范的目标 代码简洁精炼、美观&#xff0c;可持续性好高效率高复用&#xff0c;可移植性好高内聚&#xff0c;低耦合没有冗余规范性&#xff0c;代码有规可循&#xff0c;可以看出自己当时的思考过程特殊排版&#xff0c;特殊语法&#xff0c;特殊指令&#xff0c;必须…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题&#xff0c;说是客户的导入文件模版想支持部分导入内容的下拉选&#xff0c;于是我就找了easyexcel官网寻找解决方案&#xff0c;并没有找到合适的方案&#xff0c;没办法只能自己动手并分享出来&#xff0c;针对Java生成Excel下拉菜单时因选项过多导…...

Python 高效图像帧提取与视频编码:实战指南

Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...