代理模式--静态代理和动态代理
1.代理模式
定义:代理模式就是代替对象具备真实对象的功能,并代替真实对象完成相应的操作并且在不改变真实对象源代码的情况下扩展其功能,在某些情况下,⼀个对象不适合或者不能直接引⽤另⼀个对象,⽽代理对象可以在客户端和⽬标对象之间起到中介的作⽤
使用代理模式可以降低系统的耦合性,扩展性好,并且可以起到保护目标对象的作用
例如:我们平时租房的过程,租房中介就相当于代理类
代理模式分为静态代理和动态代理
2.静态代理
静态代理实现步骤:
- 定义⼀个接⼝及其实现类(目标类);
- 创建⼀个代理类同样实现这个接⼝(继承同一个接口的原因就是,代理类需要拥有和目标类同样的方法这样才能代理)
- 将⽬标对象注⼊进代理类,然后在代理类的对应⽅法调⽤⽬标类中的对应⽅法。
public interface IRentHouse {void rent();
}
public class RentHouse implements IRentHouse{@Overridepublic void rent() {System.out.println("租户租房子");}
}
public class IntermediaryProxy implements IRentHouse{private IRentHouse iRentHouse;public IntermediaryProxy(IRentHouse iRentHouse) {this.iRentHouse = iRentHouse;}@Overridepublic void rent() {System.out.println("交中介费");iRentHouse.rent();System.out.println("租房子后中介负责维护管理");}
}
/*** 测试类*/
public class Test {public static void main(String[] args) {// 定义租房IRentHouse iRentHouse = new RentHouse();// 定义中介IRentHouse proxy = new IntermediaryProxy(iRentHouse);// 租房proxy.rent();}
}
运行结果如下:

静态代理有很多缺点,实际应用场景非常少,几乎不用
对目标对象的每个方法的增强都是手动完成的,非常不灵活(比如接口中一旦新增方法,目标对象和代理对象都要修改),且麻烦(需要对每个目标类都单独写一个代理类)
3.动态代理
相比于静态代理来说,动态代理更加灵活,不需要针对每个目标类都单独创建一个代理类,也不需要我们必须实现接口
动态代理允许使用一种方法的单个类(代理类),为具有任意数量方法的任意类(目标类)的多个方法提供服务,看到这句话,是不是联想到动态代理的实现与Java反射机制密不可分
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个属性和方法,这种动态获取的信息以及动态调用对象的方法的功能称之为Java语言的反射机制
从 JVM ⻆度来说,动态代理是在运⾏时动态⽣成类字节码,并加载到 JVM 中
的。说到动态代理,不得不提的是Spring AOP,它的实现依赖了动态代理
代理类的两个作用
1.添加增强方法,2.调用目标类
1.jdk动态代理(接口代理)
在 Java 动态代理机制中java.long.reflect包中的 InvocationHandler 接⼝和 Proxy 类是核⼼
实际上就是在内存中生产一个对象,该对象实现了指定的目标对象的所有接口,代理对象和目标对象是兄弟关系,
jdk自带动态代理技术,需要使用一个静态方法来创建代理对象,他需要目标对象必须实现接口,生产的代理对象和目标对象都实现同一个接口
JDK 动态代理类使⽤步骤:
- 定义⼀个接⼝及其实现类;
- ⾃定义 InvocationHandler 并重写invoke⽅法,在 invoke ⽅法中我们会调⽤ 原⽣⽅法(被代理类的⽅法)并⾃定义⼀些处理逻辑;
- 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) ⽅法创建代理对象;
1.定义JDK动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;// JDK 动态代理类
public class JDKInvocationHandler implements InvocationHandler {//⽬标对象即就是被代理对象private Object target;public JDKInvocationHandler(Object target) {this.target = target;}/**** @param proxy 代理对象* @param method 代理方法* @param args 参数** @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 1234就是一些增强方法//1.安全检查System.out.println("安全检查");//2.记录⽇志System.out.println("记录⽇志");//3.时间统计开始System.out.println("记录开始时间");//通过反射调⽤被代理类的⽅法Object retVal = method.invoke(target, args);//4.时间统计结束System.out.println("记录结束时间");return retVal;}
}
2.创建⼀个代理对象并使用
public class Main {public static void main(String[] args) {// 代理对象PayService target= new AliPayService();// 静态的是已经写好了的// 动态的创建⼀个代理类:通过被代理类、被代理实现的接⼝、⽅法调⽤处理器来创建PayService proxy = (PayService) Proxy.newProxyInstance(// 通过目标类的getClassLoadertarget.getClass().getClassLoader(),// 被代理类实现的一些接口new Class[]{PayService.class},// 实现了InvocationHandler接口的对象new JDKInvocationHandler(target));proxy.pay();}}
Proxy 类中使⽤频率最⾼的⽅法是:newProxyInstance() ,这个⽅法主要⽤来⽣成⼀个代理对象
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{....}
这个⽅法⼀共有 3 个参数:
- loader :类加载器,⽤于加载代理对象。
- interfaces : 被代理类实现的⼀些接⼝;
- h : 实现了 InvocationHandler 接⼝的对象;
运行main方法

JDK 动态代理有⼀个最致命的问题是其只能代理实现了接⼝的类,为了解决这个问题,我们可以⽤ CGLIB 动态代理机制来避免
CGLIB(Code GenerationLibrary)是⼀个基于ASM的字节码⽣成库,它允许我们在运⾏时对字节码进⾏修改和动态⽣成。CGLIB通过继承⽅式实现代理。很多知名的开源框架都使⽤到了CGLIB, 例如 Spring 中的 AOP 模块中:如果⽬标对象实现了接⼝,则默认采⽤JDK 动态代理,否则采⽤ CGLIB 动态代理。
在 CGLIB 动态代理机制中 MethodInterceptor 接⼝和 Enhancer 类是核⼼
2.CGLIB 动态代理类使⽤步骤
- 定义⼀个类;
- ⾃定义 MethodInterceptor 并重写 intercept ⽅法,intercept ⽤于拦截增强
被代理类的⽅法,和 JDK 动态代理中的 invoke ⽅法类似; - 通过 Enhancer 类的 create()创建代理类
1.添加依赖
和JDK 动态代理不同, CGLIB(Code Generation Library) 实际是属于⼀个开源项⽬,如果你要使⽤它的话,需要⼿动添加相关依赖
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
2.⾃定义 MethodInterceptor(⽅法拦截器)
public class CGLIBInterceptor implements MethodInterceptor {//被代理对象private Object target;public CGLIBInterceptor(Object target){this.target = target;}@Overridepublic Object intercept(Object o, Method method, Object[] args, Method
Proxy methodProxy) throws Throwable {//1.安全检查System.out.println("安全检查");//2.记录⽇志System.out.println("记录⽇志");//3.时间统计开始System.out.println("记录开始时间");//通过cglib的代理⽅法调⽤Object retVal = methodProxy.invoke(target, args);//4.时间统计结束System.out.println("记录结束时间");return retVal;}
}
3.创建代理类, 并使⽤
public static void main(String[] args) {PayService target= new AliPayService();PayService proxy= (PayService) Enhancer.create(target.getClass(),ne
w CGLIBInterceptor(target));proxy.pay();}
你需要⾃定义 MethodInterceptor 并重写 intercept ⽅法,intercept ⽤于拦截增强被代理类的⽅法
public interface MethodInterceptor
extends Callback{// 拦截被代理类中的⽅法public Object intercept(Object obj, java.lang.reflect.Method method, Ob
ject[] args,MethodProxy proxy) throws Throwable;
}
- obj : 被代理的对象(需要增强的对象)
- method : 被拦截的⽅法(需要增强的⽅法)
- args : ⽅法⼊参
- proxy : ⽤于调⽤原始⽅法
3.JDK 动态代理和 CGLIB 动态代理对⽐:
- JDK 动态代理只能代理实现了接⼝的类或者直接代理接⼝,⽽ CGLIB 可以代理未实现任何接⼝的类
- CGLIB动态代理是通过⽣成⼀个被代理类的⼦类来拦截被代理类的⽅法调⽤,因此不能代理声明为 final
性能: ⼤部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显
Spring代理选择
- proxyTargetClass 为false, ⽬标实现了接⼝, ⽤jdk代理
- proxyTargetClass 为false, ⽬标未实现接⼝, ⽤cglib代理
- proxyTargetClass 为true, ⽤cglib代理
下篇见~

相关文章:
代理模式--静态代理和动态代理
1.代理模式 定义:代理模式就是代替对象具备真实对象的功能,并代替真实对象完成相应的操作并且在不改变真实对象源代码的情况下扩展其功能,在某些情况下,⼀个对象不适合或者不能直接引⽤另⼀个对象,⽽代理对象可以在客户…...
C++容器——list的模拟实现
目录 一.list的基本结构 二. 接下来就是对list类构造函数的设计了: 三.链表数据的增加: 四.接下来就是迭代器的创建了: 四.简单函数的实现: 五.构造与析构 六.拷贝构造和赋值重载 传统写法: 现代写法: 七.迭…...
VUE3 祖孙组件传值调用方法
1.在 Vue 3 中,你可以使用 provide/inject 来实现祖孙组件之间的传值和调用方法。 首先,在祖组件中使用 provide 来提供数据或方法,例如: // 祖组件 import { provide } from vue;export default {setup() {const data Hello;c…...
我的网安之路
机缘 我目前从事网安工作,一转眼我从发布的第一篇文章到现在已经过去了4年了,感慨时间过得很快 曾经我是一名Java开发工程师所以我的第一篇文章是跟开发相关的那个时候还是实习生被安排 一个很难的工作是完成地图实时定位以及根据GPS信息模拟海上追捕,这对刚入职的我来说很难 …...
langchain-ChatGLM源码阅读:webui.py
样式定制 使用gradio设置页面的视觉组件和交互逻辑 import gradio as gr import shutilfrom chains.local_doc_qa import LocalDocQA from configs.model_config import * import nltk import models.shared as shared from models.loader.args import parser from models.load…...
<C++>二、 类和对象
1.面向对象和面向过程 C语言是面向过程的,关注的是过程,分析出求解问题的步骤, 通过函数调用逐步解决问题。 C是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。 2. C类 C…...
【HttpRunnerManager】搭建接口自动化测试平台实战
目录 一、需要准备的知识点 二、我搭建的环境 三、搭建过程 四、访问链接 五、两个问题点 【整整200集】超超超详细的Python接口自动化测试进阶教程,真实模拟企业项目实战!! 一、需要准备的知识点 1. linux: 安装 python3、nginx 安装和…...
【adb】adb常用命令
Android Debug Bridge (adb) Android 调试桥 (adb) 是一种功能多样的命令行工具,可让您与设备进行通信。adb 命令可用于执行各种设备操作,例如安装和调试应用。adb 提供对 Unix shell(可用来在设备上运行各种命令)的访问权限。它…...
SAP 委外副产品业务
SAP 委外副产品业务 1.订单bom设置数量为负 2.采购收货时,副产品O库存增加,545 O 借:原材料 贷:委外加工-发出材料 3.从O库存调拨回本地库存,542...
高并发编程-2. 并发级别
此文章为笔记,为阅读其他文章的感受、补充、记录、练习、汇总,非原创,感谢每个知识分享者。 原文 文章目录 阻塞无饥饿(Starvation-Free)无障碍(Obstruction-Free)无锁(Lock-Free)无等待 由于临界区的存在,多线程之间的并发必须受…...
牛客网Verilog刷题——VL47
牛客网Verilog刷题——VL47 题目答案 题目 实现4bit位宽的格雷码计数器。 电路的接口如下图所示: 输入输出描述: 信号类型输入/输出位宽描述clkwireIntput1时钟信号rst_nwireIntput1异步复位信号,低电平有效gray_outregOutput4输出格雷码计数…...
Redis以及Java使用Redis
一、Redis的安装 Redis是一个基于内存的 key-value 结构数据库。 基于内存存储,读写性能高 适合存储热点数据(热点商品、资讯、新闻) 企业应用广泛 官网:https://redis.io 中文网:https://www.redis.net.cn/ Redis…...
Apipost教程?一篇文章玩转Apipost
你是否经常遇到接口开发过程中的各种问题?或许你曾为接口测试与调试的繁琐流程而烦恼。不要担心!今天我将向大家介绍一款功能强大、易于上手的接口测试工具——Apipost,并带你深入了解如何玩转它,轻松实现接口测试与调试。 什么是…...
微信小程序开发学习之--地图绘制行政区域图
不知道大家有没有感觉就是在做微信小程序地图功能时刚刚接触时候真的感觉好迷茫呀,文档看不懂,资料找不到,就很难受呀,比如我现在的功能就想想绘制出一个区域的轮廓图,主要是为了显眼,效果图如下࿱…...
在windows下安装ruby使用gem
在windows下安装ruby使用gem 1.下载安装ruby环境2.使用gem3.gem换源 1.下载安装ruby环境 ruby下载地址 选择合适的版本进行下载和安装: 在安装的时候,请勾选Add Ruby executables to your PATH这个选项,添加环境变量: 安装Ruby成…...
【Ajax】笔记-设置CORS响应头实现跨域
CORS CORS CORS是什么? CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持get和post请求。跨域资源共享标准新增了一组HTTP首…...
实现Feed流的三种模式:拉模式、推模式和推拉结合模式
在互联网产品中,Feed流是一种常见的功能,它可以帮助我们实时获取我们关注的用户的最新动态。Feed流的实现有多种模式,包括拉模式、推模式和推拉结合模式。在本文中,我们将详细介绍这三种模式,并通过Java代码示例来实现…...
Vue中使用Typescript及Typescript基础
准备工作 新建一个基于ts的vue项目 通过官方脚手架构建安装 # 1. 如果没有安装 Vue CLI 就先安装 npm install --global vue/cli最新的Vue CLI工具允许开发者 使用 TypeScript 集成环境 创建新项目。 只需运行vue create my-app 然后选择选项,箭头键选择 Manuall…...
MySQL数据库 【索引事务】
目录 一、概念 二、索引的优缺点 1、索引的优点 2、索引的缺陷 三、索引的使用 1、查看索引 2、创建索引 3、删除索引 四、索引底层的数据结构 1、B树 2、B树 五、索引事务 1、概念和回滚 2、事务的使用 3、事务的基本特性 4、并发会遇到的问题 (…...
源码阅读:classnames
源码阅读:classnames 源码阅读:classnames简介源码解读indexdedupebind类型声明 学习与收获 源码阅读:classnames 简介 classnames 一个简单的 JavaScript 实用程序,用于有条件地将类名连接在一起。 可以通过 npm 包管理器从 n…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
