代理模式和Java中的动态代理【开发实践】
文章目录
- 一、代理模式基础
- 1.1 代理模式
- 1.2 静态代理
- 1.3 动态代理
- 二、静态代理的实现
- 三、JDK动态代理
- 3.1 JDK动态代理概述
- 3.2 invoke方法介绍
- 3.3 JDK动态代理的使用
- 四、CGLIB动态代理
- 3.1 CGLIB动态代理概述
- 3.2 CGLIB动态代理的使用
- 五、对比
- 5.1 代理实现与使用对比
- 5.2 使用条件对比
- 5.3 增强逻辑的位置对比
一、代理模式基础
1.1 代理模式
代理模式是常见的设计模式之一,代理模式就是代理对象具备真实对象的功能,能代替真实对象完成相应操作,并能在操作执行的前后进行增强处理。
代理模式常应用于面向切面编程(AOP)、日志记录、权限控制、性能监控等多种横切关注点的系统级服务。
代理模式的实现可以分为两类:一类是静态代理,另一类是动态代理。
1.2 静态代理
静态代理在程序运行前就已经存在,指由程序员需要手动编写或使用特定工具生成代理类的源代码(即.class 文件),在程序编译阶段就已确定。
静态代理需要为每个目标类手动编写代理类,可能导致代码重复。适用于代码结构相对固定且代理类数量有限的场景。
1.3 动态代理
动态代理是在程序运行期间动态生成的。代理不是直接写成 .class 文件,而是在JVM运行时通过反射、字节码操作(如Java的 java.lang.reflect.Proxy 类或第三方库如CGLIB)等机制动态构建的。
动态代理提供了更高的灵活性和扩展性,但会牺牲少许性能。
二、静态代理的实现
先理解静态代理的实现,更容易理解JDK动态代理的原理,其使用流程如下:
- 定义一个接口,里面有需要被代理/增强的方法。
- 定义一个需要被代理的类,实现上述接口。
- 定义一个静态代理类,也实现上述接口,并且需要定义接口类型的成员变量,用于指向被代理的对象。在静态代理类中,可以对接口方法进行增强,内部可以调用被代理对象的对应方法,并在前后做增强处理。
- 使用时,用接口申明变量类型,指向静态代理类的实例对象。
// 接口
interface Subject {// 需要被增强的方法void request();
}// 实现类
class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject: Handling request.");}
}// 静态代理类
class StaticProxy implements Subject {// 成员变量用于指向被代理的对象,使用接口类型申明该变量private final Subject realSubject;// 可以用构造器或者set方法来设置被代理的对象public StaticProxy(Subject realSubject) {this.realSubject = realSubject;}@Overridepublic void request() {// 可选的前置处理preRequest();// 调用被代理的对象realSubject.request();// 可选的后置处理postRequest();}private void preRequest() {System.out.println("StaticProxy: Pre-processing request.");}private void postRequest() {System.out.println("StaticProxy: Post-processing request.");}
}// 使用静态代理对象
public class StaticProxyTest {public static void main(String[] args) {// 使用接口申明变量类型,指向静态代理类的实例对象Subject subject = new StaticProxy(new RealSubject());subject.request();}
}
三、JDK动态代理
3.1 JDK动态代理概述
JDK动态代理是一种利用Java反射机制在运行时动态创建代理对象的技术,它是Java原生支持的,主要依赖于java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。
JDK 动态代理基于接口,只有实现了接口的类,才能通过 JDK 动态代理来增强接口方法。
3.2 invoke方法介绍
- Object proxy:代理对象的引用。尽管在invoke方法内部可能不需要直接使用它,但它代表了代理实例本身,有时候可用于获取代理类的信息或其他特殊处理。
- Method method:表示被调用的方法的一个Method对象。这个对象包含了方法的所有元数据,如方法名、返回类型、参数类型等。你可以利用这个对象来判断被调用的是哪个具体方法,从而做出不同的处理逻辑。
- Object[] args:一个对象数组,包含了调用方法时传递的实际参数。这些参数与原始方法调用时提供的参数类型和顺序完全一致。你可以利用这些参数来传递给被代理方法,或者进行预处理/后处理
- 返回值:invoke方法的返回值会作为实际调用方法的返回值。
3.3 JDK动态代理的使用
JDK动态代理的使用流程如下:
- 定义一个接口,里面有需要被代理/增强的方法。
- 定义一个需要被代理的类,实现上述接口。
- 定义一个动态代理处理器,需要实现
InvocationHandler接口,并且需要定义接口类型的成员变量,用于指向被代理的对象。实现invoke()方法,可以对接口方法进行增强。 - 使用时,用接口申明变量类型,指向
Proxy.newProxyInstance()返回的代理对象。
// 动态代理处理器
class DynamicProxyHandler implements InvocationHandler {private final Subject realSubject;public DynamicProxyHandler(Subject realSubject) {this.realSubject = realSubject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {preRequest();// 调用被代理对象的方法// 调用接口方法时,这里就会调用被代理对象的相应方法Object result = method.invoke(realSubject, args);postRequest();return result;}private void preRequest() {System.out.println("DynamicProxyHandler: Pre-processing request.");}private void postRequest() {System.out.println("DynamicProxyHandler: Post-processing request.");}
}// 测试动态代理
public class DynamicProxyTest {public static void main(String[] args) {Subject realSubject = new RealSubject();// 返回的是Object对象,需要转换为目标接口对象Subject proxySubject = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(),new Class[]{Subject.class},new DynamicProxyHandler(realSubject));proxySubject.request();}
}
四、CGLIB动态代理
3.1 CGLIB动态代理概述
CGLIB(Code Generation Library)是一个强大的、高性能的代码生成库,它允许在运行时动态地生成和修改Java字节码。
CGLIB动态代理基于子类继承,能够对任何类(无论是否实现了接口)实现代理,这使得它的应用范围更广。
3.2 CGLIB动态代理的使用
CGLIB动态代理的使用流程如下:
- 定义目标类(无需实现接口)。
- 定义方法拦截器,需要实现
MethodInterceptor接口。实现intercept()方法来对被代理对象的方法进行增强。 - 使用时,需要创建方法拦截器对象和
Enhancer对象,通过Enhancer对象来返回代理对象。该操作可以封装在方法拦截器中。
// 目标类,无需实现接口
class RealSubject {public void request() {System.out.println("RealSubject: Handling request.");}
}// CGLIB代理实现
class CglibProxy implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {preRequest();Object result = proxy.invokeSuper(obj, args); // 调用父类方法,即真实对象的方法postRequest();return result;}private void preRequest() {System.out.println("CglibProxy: Pre-processing request.");}private void postRequest() {System.out.println("CglibProxy: Post-processing request.");}// 创建代理对象public Object getProxy(Class<?> clazz) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(clazz); // 设置父类enhancer.setCallback(this); // 设置回调方法return enhancer.create(); // 创建并返回代理对象}
}// 测试CGLIB动态代理
public class CglibProxyTest {public static void main(String[] args) {CglibProxy cglibProxy = new CglibProxy();// 返回的是Object对象,需要转换为被代理类的对象RealSubject proxySubject = (RealSubject) cglibProxy.getProxy(RealSubject.class);proxySubject.request();}
}
五、对比
5.1 代理实现与使用对比
实现代理逻辑
都需要调用目标方法,然后在目标方法前后新增增强逻辑。区别是,静态代理在实现接口方法时,调用被代理对象的目标方法并实现增强。动态代理需要实现接口(InvocationHandler / MethodInterceptor),必须实现接口方法(invoke / intercept),在接口方法里调用被代理对象的目标方法并实现增强。
获取代理对象
静态代理时,被代理类的对象即代理对象。
JDK动态代理中,使用Proxy.newProxyInstance()来获取代理对象。
CGLIB动态代理中,使用enhancer.create()来获取代理对象。
5.2 使用条件对比
静态代理和CGLIB动态代理都依赖于接口,CGLIB动态代理不依赖于接口。
5.3 增强逻辑的位置对比
静态代理中,增强逻辑分散在被代理类的各个方法中,需要在方法中实现该方法的增强逻辑。如果这些方法都需要同种增强,将产生大量的重复代码。
在动态代理中,增强逻辑集中在一个方法里。如果所有方法都需要同种增强,增强逻辑只需要写一处,非常方便。如果方法的增强逻辑不同,则需要通过反射获取方法名,然后使用响应的增强逻辑。
相关文章:
代理模式和Java中的动态代理【开发实践】
文章目录 一、代理模式基础1.1 代理模式1.2 静态代理1.3 动态代理 二、静态代理的实现三、JDK动态代理3.1 JDK动态代理概述3.2 invoke方法介绍3.3 JDK动态代理的使用 四、CGLIB动态代理3.1 CGLIB动态代理概述3.2 CGLIB动态代理的使用 五、对比5.1 代理实现与使用对比5.2 使用条…...
【Linux】进程间通信——匿名管道
目录 为什么要进行进程间通信? 匿名管道的具体实现 pipe创建内存级文件形成管道 pipe的简单使用 匿名管道的四种情况和五种特性 四种情况 五种特性 PIPE_BUF 命令行管道 | 功能代码:创建进程池 为什么要进行进程间通信? 1.数据传输&…...
React Native与React Native Web:跨平台开发的新选择
React Native和React Native Web是两种基于React框架的跨平台开发技术,它们分别针对原生移动应用和Web应用的开发,但都提供了统一的开发体验和代码复用能力。 React Native 概述 React Native允许开发者使用React的组件化思想和JavaScript编写原生级别…...
【从零开始实现stm32无刷电机FOC】【理论】【3/6 位置、速度、电流控制】
目录 PID控制滤波单独位置控制单独速度控制单独电流控制位置-速度-电流串级控制 上一节,通过对SVPWM的推导,我们获得了控制电机转子任意受力的能力。本节,我们选用上节得到的转子dq轴解耦的SVPWM形式,对转子受力进行合理控制&…...
使用MySQLInstaller配置MySQL
操作步骤 1.配置High Availability 默认选项Standalone MySQL Server classic MySQL Replication 2.配置Type and Networking ◆端口默认启用TCP/P网络 ◆端口默认为3306 3.配置Account and Roles 设置root账户的密码、添加其他管理员 4.配置Windows Service ◆配置MySQL Serv…...
命令执行(RCE)面对各种过滤,骚姿势绕过总结
1、什么是RCE RCE又称远程代码执行漏洞,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统。 2、RCE产生原因 服务器没有对执行命令的函数做严格的过滤,最终导致命令被执行。 3、命令执行函数 PHP代码执行函数…...
复杂的数仓项目,涵盖了从数据采集、处理、存储到可视化的整个流程
一个复杂的数仓项目,涵盖了从数据采集、处理、存储到可视化的整个流程。以下是对您提供信息的梳理和解释: 1. **项目架构**: - 包含实时流、离线流和配置流三条数据流。 - 数据源使用MySQL,开启binlog日志。 2. **数据采集…...
三相感应电机的建模仿真(3)基于ABC相坐标系Level2 S-Fun以及定子串不对称电抗起动过程仿真分析
1. 概述 2. 三相感应电动机状态方程式 3. 基于Level2 S-Function的仿真模型建立 4. 动态分析实例 5. 总结 6. 参考文献 1. 概述 三相感应电机自然坐标系下的数学模型是一组周期性变系数微分方程(其电感矩阵是转子位置角的函数,转子位置角随时间按正弦规律变化),将其用…...
了解Adam和RMSprop优化算法
优化算法是机器学习和深度学习模型训练中至关重要的部分。本文将详细介绍Adam(Adaptive Moment Estimation)和RMSprop(Root Mean Square Propagation)这两种常用的优化算法,包括它们的原理、公式和具体代码示例。 RMS…...
对于配置LLM,集显和独显的具体区别和影响
在配置大型语言模型(LLM)时,集成显卡(集显)和独立显卡(独显)之间的区别和影响主要体现在以下几个方面: 1. 性能差异 集成显卡(集显): 集显通常集…...
uniapp上架到appstore遇到的问题
1、appstore在美国审核,需要把服务器接口的国外访问权限放开 2、登陆部分 a、审核时只能有密码登陆,可以通过接口响应参数将其他登陆方式暂时隐藏,审核成功后放开即可 b、需要有账号注销功能 3、使用照相机和相册功能时需要写清楚描述文案...
每天10个vue面试题(一)
1. Vue的基本原理? 当一个Vue实例创建时,Vue会遍历data中的属性,用Object.defineProperty(vue3.0使用proxy )将它们转为 getter/setter,并且在内部追踪相关依赖,在属性被访问和修改时通知变化。…...
【博主推荐】HTML5好看的酷酷的个人简历、个人主页、个人网站源码
文章目录 1.设计来源1.1 主界面1.2 关于我界面1.3 我的项目界面1.4 我的经验界面1.5 我的技能界面1.6 我的文章界面1.7 联系我界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板,程序开发,在线开发,在线沟通 作者:xcLeig…...
【深度学习】PyTorch深度学习笔记01-Overview
参考学习:B站视频【《PyTorch深度学习实践》完结合集】-刘二大人 ------------------------------------------------------------------------------------------------------- 1. 基于规则的深度学习 2. 经典的机器学习——手动提取一些简单的特征 3. 表示学习…...
IDEA新建项目并撰写Java代码的方法
本文介绍在IntelliJ IDEA软件中,新建项目或打开已有项目,并撰写Java代码的具体方法;Groovy等语言的代码也可以基于这种方法来撰写。 在之前的文章IntelliJ IDEA社区版在Windows电脑中的下载、安装方法(https://blog.csdn.net/zheb…...
24-7-9-读书笔记(九)-《爱与生的苦恼》[德]叔本华 [译]金玲
文章目录 《爱与生的苦恼》阅读笔记记录总结 《爱与生的苦恼》 《爱与生的苦恼》叔本华大佬的名书,里面有其“臭名昭著”的《论女人》,抛开这篇其他的还是挺不错的,哲学我也是一知半解,这里看得也凭喜好,这里记录一些自…...
uniapp本地打包到Android Studio生成APK文件
(1)安装 Android Studio 软件; 下载地址:官方下载地址,英文环境 安装:如下之外,其他一键 next (2)配置java环境; 下载:j…...
如何设计一个高可扩展的分布式架构?
如何设计一个高可扩展的分布式架构? 大家好,我是微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 1. 引言:分布式架构的重要性 随着互联网应用的发展,单一服务器往往难以满足…...
大话C语言:第28篇 内存分配与释放
1 malloc函数 函数说明: #include <stdlib.h>void *malloc(size_t size); 功能:在内存的动态存储区(堆区)中分配一块长度为size字节的连续区域,用来存放类型说明符指定的类型。分配的内存空间内容不确定。 参数:size&…...
第一个基于FISCOBCOS的前后端项目(发行转账)
本文旨在介绍一个简单的基于fiscobcos的前后端网站应用。Springbootjs前后端不分离。 所使用到的合约也是一个最基本的。首先您需要知道的是完整项目分为三部分,1是区块链平台webase搭建(此项目使用节点前置webase-front即可),2是…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
