动态代理:面向接口编程,屏蔽RPC处理过程
RPC远程调用
使用 RPC 时,一般的做法是先找服务提供方要接口,通过 Maven把接口依赖到项目中。在编写业务逻辑的时候,如果要调用提供方的接口,只需要通过依赖注入的方式把接口注入到项目中,然后在代码里面直接调用接口的方法 。
接口里并不会包含真实的业务逻辑,业务逻辑都在服务提供方。
核心技术:动态代理。
RPC 会自动给接口生成一个代理类,项目中注入接口的时候,运行过程中实际绑定的是这个接口生成的代理类。在接口方法被调用的时候,实际上是被生成代理类拦截到,这样就可以在生成的代理类里面,加入远程调用逻辑。
流程如下:

实现原理
jdk动态代理:
/*** 要代理的接口*/
public interface Hello {String say();
}/*** 真实调用对象*/
public class RealHello {public String haha(){return "i'm proxy";}
}
代理类实现InvocationHandler接口
/*** JDK代理类生成*/
public class JDKProxy implements InvocationHandler {private Object target;JDKProxy(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] paramValues) {return ((RealHello)target).haha();}
}public class TestProxy {public static void main(String[] args){// 构建代理器JDKProxy proxy = new JDKProxy(new RealHello());ClassLoader classLoader = Hello.class.getClassLoader();// 把生成的代理类保存到文件
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");// 生成代理类Hello test = (Hello) Proxy.newProxyInstance(classLoader, new Class[]{Hello.class}, proxy);// 方法调用System.out.println(test.say());}
}
解释:给 Hello 接口生成一个动态代理类,并调用接口 say() 方法,但真实返回的值是来自 RealHello 里面的 haha() 方法返回值。
重点是代理类的生成,Proxy.newProxyInstance。
参数 saveGeneratedFiles 来控制是否把生成的字节码保存到本地磁盘。
key为“sun.misc.ProxyGenerator.saveGeneratedFiles”的Property来控制的,动态生成的类会保存在工程根目录下的 com/sun/proxy 目录里面。
生成的代理类。

package com.sun.proxy;import com.lkl.proxy.Hello;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy0 extends Proxy implements Hello {private static Method m1;private static Method m2;private static Method m3;private static Method m0;public $Proxy0(InvocationHandler var1) throws {super(var1);}public final boolean equals(Object var1) throws {try {return (Boolean)super.h.invoke(this, m1, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final String toString() throws {try {return (String)super.h.invoke(this, m2, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final String say() throws {try {// 代理类执行return (String)super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final int hashCode() throws {try {return (Integer)super.h.invoke(this, m0, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m2 = Class.forName("java.lang.Object").getMethod("toString");m3 = Class.forName("com.lkl.proxy.Hello").getMethod("say");m0 = Class.forName("java.lang.Object").getMethod("hashCode");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
}
$Proxy0 类里面有一个跟 Hello 一样签名的 say() 方法,其中 this.h 绑定的是刚才传入的 JDKProxy 对象,所以当调用 Hello.say() 的时候,实际被转发到了JDKProxy.invoke()。
单纯从代理功能上来看,JDK 默认的代理功能是有一定的局限性的,要求被代理的只能是接口。原因是生成的代理类会继承 Proxy 类,但Java不支持多重继承。
JDK默认的代理功能,最大的问题就是性能问题。生成后的代理类是使用反射来完成方法调用,而这种方式相对直接用编码调用来说,性能会降低,但JDK8及以上版本对反射调用的性能有很大的提升。
除了JDK 默认的nvocationHandler能完成代理功能,还有很多其他的第三方框架也可以实现,比如Javassist、Byte Buddy 这样的框架。
Javassist定位是能够操纵底层字节码,要生成动态代理类比较复杂。但是,通过Javassist生成字节码,不需要通过反射完成方法调用,所以性能会高一些。问题:通过Javassist生成一个代理类后,此 CtClass 对象会被冻结起来,不允许再修改;否则,再次生成时会报错。
Byte Buddy提供了更容易操作的API,编写的代码可读性更高。并且生成的代理类执行速度比Javassist更快。
动态代理框架选型
三个角度考虑:
- 代理类是在运行中生成的,那么代理框架生成代理类的速度、生成代理类的字节码大小等等,都会影响到其性能——生成的字节码越小,运行所占资源就越小。
- 生成的代理类,是用于接口方法请求拦截的,所以每次调用接口方法的时候,都会执行生成的代理类,生成的代理类的执行效率就需要很高效。
- 从使用角度出发的,选择使用起来很方便、好上手的代理类框架。
相关文章:
动态代理:面向接口编程,屏蔽RPC处理过程
RPC远程调用 使用 RPC 时,一般的做法是先找服务提供方要接口,通过 Maven把接口依赖到项目中。在编写业务逻辑的时候,如果要调用提供方的接口,只需要通过依赖注入的方式把接口注入到项目中,然后在代码里面直接调用接口…...
HTTP 405 Method Not Allowed:解析与解决
HTTP 405 Method Not Allowed:解析与解决 引言 在Web开发中,HTTP状态码是服务器与客户端之间通信的重要组成部分。当我们使用Python进行网络请求时,经常会遇到各种HTTP状态码。其中,HTTP 405 “Method Not Allowed” 错误是一个…...
推荐一款CAD/CAM设计辅助工具:Mastercam
Mastercam是一款非常好用的软件,我们的这款软件是由美国CNC软件公司开发,集平面制图、三维设计、曲面设计、数 控编程、刀具处理等多项强大功能于一体。软件的使用过程具有非常直观的特点,用户可以很方便地对自己的作品进行设计。 Mastercam不…...
位运算刷题记录
1. 使两个整数相等的位更改次数 3226. 使两个整数相等的位更改次数 给你两个正整数 n 和 k。 你可以选择 n 的 二进制表示 中任意一个值为 1 的位,并将其改为 0。 返回使得 n 等于 k 所需要的更改次数。如果无法实现,返回 -1。 class Solution {pub…...
爬虫技术——小白入狱案例
知孤云出岫 目录 1. 案例概述2. 案例需求分析3. 实现步骤Step 1: 环境准备Step 2: 分析百度图片URL请求规律Step 3: 编写爬虫代码代码解析 4. 运行代码5. 注意事项6. 案例总结 要实现大批量爬取百度图片,可以使用Python编写一个网络爬虫,通过发送HTTP请求…...
vue 果蔬识别系统百度AI识别vue+springboot java开发、elementui+ echarts+ vant开发
编号:R03-果蔬识别系统 简介:vuespringboot百度AI实现的果蔬识别系统 版本:2025版 视频介绍: vuespringboot百度AI实现的果蔬识别系统前后端java开发,百度识别,带H5移动端,mysql数据库可视化 1 …...
全新更新!Fastreport.NET 2025.1版本发布,提升报告开发体验
在.NET 2025.1版本中,我们带来了巨大的期待功能,进一步简化了报告模板的开发过程。新功能包括通过添加链接报告页面、异步报告准备、HTML段落旋转、代码文本编辑器中的文本搜索、WebReport图像导出等,大幅提升用户体验。 FastReport .NET 是…...
信息学科平台系统设计与实现:Spring Boot技术手册
5系统详细实现 5.1 用户信息管理 基于保密信息学科平台系统的系统管理员可以对用户信息查询。具体界面的展示如图5.1所示。 图5.1 用户信息管理界面 5.2 教师信息管理 管理员可以对教师信息进行查下和删除。具体界面如图5.2所示。 图5.2 教师信息界面 5.3 学科动态管理 管理…...
conda下jupyterlab安装问题以及交互绘图问题记录
安装 1. 直接conda install jupyterlab就好,只要在base环境下安装就行,可以在任意环境下执行jupyter lab启动。 2. 打开jupyter lab后显示Could not determine jupyterlab build status without nodejs,可以执行conda install nodejs安装no…...
尚硅谷react教程_扩展_setState更新状态的2种写法
1.setState setState更新状态的2种写法(1).setState(stateChange,[callback])----对象式的setState1.stateChange为状态改变对象(该对象可以体现出状态的更改)2.callback是可选的回调函数,它在状态更新完毕、界面也更新…...
C语言编写的自动取款机模拟程序
#include〈stdio。h> #include<string。h> #include <stdio.h> #include〈stdlib.h〉 #include〈direct.h〉 #include<io.h> #include 〈errno。h> /********************************************************…...
【常用数据结构】开发中常用的数据结构?
开发中常用的数据结构包括数组、链表、栈、队列、树、图、堆和散列表(哈希表)。这些数据结构在软件开发中有着广泛的应用,并且各自具有独特的特点和用途。 数组 数组是最基本的数据结构之一,用于在内存中连续存储多个元素。数…...
OCC 点云
OCC的基础知识可能还是要系统学习一下,部分导入的模型面类型是很多面都是GeomAbs_BSplineSurface,最终获取参数都要拟合一下,拟合后的生成的面对象没有大小,比如平面只有矢量(大小没有思路) 圆柱拟合面没有…...
方法重写与方法重载
1. 方法重载与方法重写的定义 方法重写(Overriding) 方法重写(Overriding)是指在子类中重新定义与父类中相同的方法。此操作允许子类提供特定的实现,以替代父类的实现。方法重写是实现多态性(Polymorphis…...
Vue3实现地球上加载柱体
最终效果为上图。 实现该技术,需要一些技术,我分别罗列一下: canvas:需要使用canvas根据json来绘制地球,不懂的可以看这篇canvas绘制地球 threejs:需要会使用threejs,这里并没有使用shader&am…...
OpenGL入门003——使用Factory设计模式简化渲染流程
前面两节已经学会了如何使用opengl创建窗口并绘制三角形,我们可以看出有些步骤是固定的,而且都写在main.cpp,这一节我们将了解如何使用Factroy设计模型。将模型渲染逻辑封装在一个单独的类中,简化开发流程,且提高代码复…...
01_AI编程案例展示:借助AI轻松爬取海量网盘链接
爬虫案例展示 今天,我们将展示如何利用AI快速开发一个网络爬虫, 使用的工具是Python和Claude 3.5 Sonnet(国内可用豆包替代) 我们的目标是爬取panhub.fun网站上的夸克网盘链接, 即使你是编程新手,也可以轻松完成这样的任务。 案例1-批量爬取panhub网盘整合包 下…...
【机器学习导引】ch5-神经网络
Q&A 1x1 卷积层在深度学习中的作用? 1x1 卷积层在深度学习中具有几个重要的作用: 通道压缩:1x1卷积可以通过调整输出通道数来减少特征图的深度,从而降低计算成本和参数数量。这有助于在保持特征的情况下简化模型。特征融合&am…...
【Axure原型分享】颜色选择器——填充颜色
今天和大家分享颜色选择器——填充颜色的原型模板,点击颜色区域可以弹出颜色选择器,点击可以选择对应颜色,颜色区域会变色我们选择的颜色,具体效果可以观看下方视频或者打开预览地址体验。 【原型效果】 【Axure高保真原型】颜色…...
怎么安装行星减速电机才是正确的
行星减速电机由于其高效、精密的传动能力,广泛应用于自动化设备、机器人、机床以及其他需要精准控制的领域。正确的安装行星减速电机对于确保设备的性能与延长使用寿命至关重要。 一、前期准备 在进行行星减速电机的安装之前,必须做好充分的前期准备工作…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...
ubuntu22.04 安装docker 和docker-compose
首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...
flow_controllers
关键点: 流控制器类型: 同步(Sync):发布操作会阻塞,直到数据被确认发送。异步(Async):发布操作非阻塞,数据发送由后台线程处理。纯同步(PureSync…...
rm视觉学习1-自瞄部分
首先先感谢中南大学的开源,提供了很全面的思路,减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接:https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架: 代码框架结构:readme有…...
MySQL体系架构解析(三):MySQL目录与启动配置全解析
MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录,这个目录下存放着许多可执行文件。与其他系统的可执行文件类似,这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中,用…...
