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

【Java动态代理如何实现】

在这里插入图片描述

✅Java动态代理如何实现

    • ✅JDK动态代理和Cglib动态代理的区别
  • ✅拓展知识仓
    • ✅静态代理和动态代理的区别
    • ✅动态代理的用途
    • ✅Spring AOP的实现方式
    • 📑JDK 动态代理的代码段
    • 📑Cglib动态代理的代码块
  • ✅注意事项:


在Java中,实现动态代理有两种方式:


1 . JDK动态代理 : Java.lang.reflect 包中的Proxy类和 InvocationHandler 接口提供了生成动态代理类的能力。


2 . Cglib动态代理 : Cglib (Code Generation Library) 是一个第三方代码生成类库,运行时在内存中动态生成一个了类对象从而实现对目标对象功能的扩展。


用一张图片看一下什么是动态代理(概念):

在这里插入图片描述


✅JDK动态代理和Cglib动态代理的区别


JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类就可以使用CGLIB实现。


Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的 interception (拦截)。


Calib包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它需要你对JVM内部结构包括class文件的格式和指令集都很熟悉。


所以,使用JDK动态代理的对象必须实现一个或多个接口:而使用cgib代理的对象则无需实现接口,达到代理类无侵入。


✅拓展知识仓

✅静态代理和动态代理的区别


最大的区别就是静态代理是编译期确定的,但是动态代理却是运行期确定的。




同时,使用静态代理模式需要程序员手写很多代码,这个过程是比较浪费时间和精力的。一旦需要代理的类中方法比较多,或者需要同时代理多个对象的时候,这无疑会增加很大的复杂度。


反射是动态代理的实现方式之一。

✅动态代理的用途


Java的动态代理,在日常开发中可能并不经常使用,但是并不代表他不重要。Java的动态代理的最主要的用途就是应用在各种框架中。因为使用动态代理可以很方便的运行期生成代理类,通过代理类可以做很多事情,比如AOP,比如过滤器、拦截器等。


在我们平时使用的框架中,像 servlet 的 filter 、包括 spring 提供的 aop 以及 struts2 的拦截器都使用了动态代理功能。我们日常看到的mybatis分页插件,以及日志拦截、事务拦截、权限拦截这些几乎全部由动态代理的身影。


✅Spring AOP的实现方式


Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。


JDK 动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK 动态代理的核心是 InvocationHandler 接 和 Proxy 类。


如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。


CGLIB (Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。


📑JDK 动态代理的代码段


public class UserServiceImpl implements UserService {@Overridepublic void add() {// TODO Auto-generated method stubSystem,out,println("--------------------add----------------------");}
}public class MyInvocationHandler implements InvocationHandler {private Object target;public MyInvocationHandler(Object target) {super();this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {PerformanceMonior.begin(target.getClass().getlame( )+"+method.getlame());//System.out .println("-----------------begin “+method.getName()+"---------);Object result = method.invoke(target, args);//System.out.println("--------------end "+method.getName( )+"-----);PerformanceMonior.end();return result;}public Object getProxy() {return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(),this);}
}public static void main(string[] args) {UserService seryice = new UserServiceImpl();MyInvocationHandler handler = new MyInvocationHandler(service);UserService proxy = (UserService) handler.getProxy();proxy .add();
}

📑Cglib动态代理的代码块


public class UserServiceImpl implements UserService {@Overridepublic void add() {//TODO Auto-generated method stubSystem.out,println("--------------------add----------------------");}}public class CglibProxy implements MethodInterceptor {private Enhancer enhancer = new Enhancer();public Object getProxy(Class clazz) {//设置需要创建子类的类enhancer.setSuperclass(clazz);enhancer.setCallback(this);//通过字节码技术动态创建子类实例return enhancer.create();}//实现MethodInterceptor接口方法public Object intercept(Object obj,Method method, Object[] args,MethodProxy proxy) throws Throwable {System.out.println("前置代理");//通过代理类调用父类中的方法Object result = proxy.invokeSuper(obj, args);System.out.printIn("后置代理");return result;}
}public class DoCGLib {public static void main(String[] args) {CglibProxy proxy = new CglibProxy();//通过生成子类的方式创建代理类UsenServiceImpl proxyImp = (UsenServiceImpl)proxy.getProxy(UserServiceImpl.class);proxyImp.add():}
}

✅注意事项:

JDK动态代理只能用于接口,不能用于类。

  • 动态代理只对方法调用有效,对字段访问和赋值无效
  • 如果目标对象抛出了异常,那么这个异常会被代理对象抛出,而不是在调用invoke方法时抛出

与CGLIB等其他代理技术的比较:


  • CGLIB:它是一个强大的高性能的代码生成库,可以扩展JAVA类和实现JAVA接口。它主要应用于高级OOP设计和应用,如AOP实现、缓存框架、事务管理等。
  • 两者的选择:如果你的目标是基于现有类的行为进行拦截或修改,可以使用CGLIB;如果目标是基于接口进行拦截或修改,那么应该使用JDK动态代理。

💡思考:


除了JDK动态代理和CGLIB,还有其他一些常用的代理技术,如Spring AOP、AspectJ等。这些技术提供了更高级的特性,如支持方法级别的拦截、支持运行时和编译时切面等。


// 导入java.lang.reflect包中的InvocationHandler和Proxy类  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Proxy;  // 定义一个接口Hello  
interface Hello {  // 定义接口方法sayHello,没有实现  void sayHello();  
}  // 定义一个实现Hello接口的类HelloImpl  
class HelloImpl implements Hello {  // 实现接口方法sayHello  public void sayHello() {  System.out.println("Hello, world!");  }  
}  // 定义一个实现InvocationHandler接口的类DynamicProxyHandler  
class DynamicProxyHandler implements InvocationHandler {  // 私有成员变量obj,用来保存目标对象的引用  private Object obj;  // 构造方法,传入目标对象作为参数,赋值给obj成员变量  public DynamicProxyHandler(Object obj) { this.obj = obj; }  // 实现InvocationHandler接口的方法invoke,传入代理对象、方法、参数数组,返回值类型为Object  public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {  // 在目标方法执行前输出"Before method call"  System.out.println("Before method call");  // 调用目标方法,传入参数args,返回值赋值给result变量  Object result = m.invoke(obj, args);   // 在目标方法执行后输出"After method call"  System.out.println("After method call");  // 返回目标方法的返回值或者异常(如果目标方法抛出了异常)  return result;    }  
}  public class DynamicProxyExample {  public static void main(String[] args) {  // 创建一个HelloImpl类的实例作为目标对象,并实现Hello接口的sayHello方法  Hello hello = new HelloImpl();   // 创建一个DynamicProxyHandler类的实例作为InvocationHandler,传入目标对象实例作为参数传入构造器中  InvocationHandler handler = new DynamicProxyHandler(hello);   /** 使用Proxy类的静态方法newProxyInstance创建代理对象实例,传入目标对象的类加载器、目标对象的接口数组以及* InvocationHandler实例作为参数传入构造器中。返回的是代理对象实例,类型为目标对象的接口类型。* 创建的代理对象实例可以直接像目标对象实例一样使用,只不过它实现了所有接口中的方法。* 所有这些方法的调用最终会调用到我们提供的InvocationHandler实例中对应的invoke方法中去处理。* 这样我们就能够在不修改原有代码的基础上为某个对象提供额外行为操作,* 也就是实现了在运行时动态扩展了某个类的行为功能操作,即实现了AOP的功能。* 这样就达到了在不修改原有代码的基础上扩展了某个类的行为功能操作的目的。* 比如可以在目标对象方法执行前后添加额外的逻辑操作处理。此处因为动态代理的目标是Hello接口,所以没有错误。*/ Hello proxy = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), new Class[] { Hello.class }, handler); }   
}

最后总结一下JDK动态代理的思想:

在这里插入图片描述

相关文章:

【Java动态代理如何实现】

✅Java动态代理如何实现 ✅JDK动态代理和Cglib动态代理的区别 ✅拓展知识仓✅静态代理和动态代理的区别✅动态代理的用途✅Spring AOP的实现方式📑JDK 动态代理的代码段📑Cglib动态代理的代码块 ✅注意事项: 在Java中,实现动态代理…...

数据库(部分函数)

函数: 单行函数:会对查询中的每一数据进行处理 字符函数 length(列名) select name, 日期函数: now() 年月日时分秒 curdate() 年月日 curtime()时分秒 …...

基于Vite+Vue3 给项目引入Axios

基于ViteVue3 给项目引入Axios,方便与后端进行通信。 系列文章指路👉 系列文章-基于Vue3创建前端项目并引入、配置常用的库和工具类 文章目录 安装依赖新建src/config/config.js 用于存放常用配置进行简单封装解决跨域问题调用尝试 安装依赖 npm install axios …...

为什么查企业的时候有的公司没有显示注册资金?

我们在查询企业信息时,有时候会遇到某一家企业没有注册资金的情况,但是该企业又不是已经注销的。出现这种情况是什么原因呢? 1.该公司是一家分公司,分公司没有独立法人资格,因此没有注册资金。 2.有些情况下&#xf…...

DataProcess-VOC数据图像和标签一起进行Resize

VOC数据图像和标签一起进行Resize 参加检测比赛的时候,很多时候工业原始数据尺度都比较大,如果对数据不提前进行处理,会导致数据在加载进内存时花费大量的时间,所以在执行训练程序之前需要将图像提前进行预处理。对于目标检测的数…...

MultiValueMap

MultiValueMap是Spring框架中提供的一个接口,它继承了Map接口,用于存储键值对,但与普通的Map不同的是,MultiValueMap中一个键可以对应多个值,因此它也可以被称为“多值Map”。 MultiValueMap的使用场景一般是在需要存…...

山西电力市场日前价格预测【2023-12-25】

日前价格预测 预测说明: 如上图所示,预测明日(2023-12-25)山西电力市场全天平均日前电价为469.89元/MWh。其中,最高日前电价为1048.40元/MWh,预计出现在08:30。最低日前电价为252.77元/MWh,预计…...

【华为OD机试真题2023CD卷 JAVAJS】5G网络建设

华为OD2023(C&D卷)机试题库全覆盖,刷题指南点这里 5G网络建设 时间限制:4s 空间限制:256MB 限定语言:不限 题目描述: 现需要在某城市进行5G网络建设,已经选取N个地点设置5G基站,编号固定为1到N,接下来需要各个基站之间使用光纤进行连接以确保基站能互联互通,不同…...

OSI 七层参考模型及TCP/IP 四层模型

OSI 七层参考模型 七层模型,亦称 OSI ( Open System Interconnection )参考模型,即开放式系统互联。参考模型是国际标准化组织(ISO )制定的一个用于计算机或通信系统间互联的标准体系,一般称为…...

【面向对象】对比JavaScript、Go、Ada、Python、C++、Java、PHP的访问限制。

在不同编程语言中,控制成员(变量、方法、类等)可见性的机制不尽相同。以下是对比JavaScript、Go、Ada、Python、C、Java、PHP所使用的访问限制关键字和约定: 一、JavaScript ### JavaScript访问限制 早期的JavaScript并没有类似…...

力扣(leetcode)第26题删除有序数组中的重复项(Python)

26.删除有序数组的重复项 题目链接:26.删除有序数组的重复项 给你一个非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 …...

【内存泄漏】内存泄漏及常见的内存泄漏检测工具介绍

内存泄漏介绍 什么是内存泄漏 内存泄漏是指程序分配了一块内存(通常是动态分配的堆内存),但在不再需要这块内存的情况下未将其释放。内存泄漏会导致程序浪费系统内存资源,持续的内存泄漏还导致系统内存的逐渐耗尽,最…...

FPGA-ZYNQ-7000 SoC在嵌入式系统中的优势

FPGA-ZYNQ-7000 SoC在嵌入式系统中的优势 本章节主要参考书籍《Xilinx Zynq-7000 嵌入式系统设计与实现 基于ARM Cortex-A9双核处理器和Vivado的设计方法 (何宾,张艳辉编著)》 本章节主要讲述FPGA-ZYNQ-7000 SoC在嵌入式系统中的优势,学习笔…...

如何在Vue3中实现无缝热重载:提升你的开发效率

Vue3中的热重载(Hot Module Replacement,简称HMR)是一种开发时的功能,它允许开发者在不刷新整个页面的情况下,实时替换、添加或删除模块。这意味着当你对Vue组件进行修改并保存时,这些更改会立即反映在浏览…...

盒子 Box

UVa1587 思路&#xff1a; 1.输入每个面的长宽并将每个面较长的一边放在前面 2.判断是否存在三对面分别相等 3.判断是否存在三组四棱相等 #include <stdio.h> #include <stdlib.h> #define maxn 100int cmp(const void* e1, const void* e2) {return (int)(*(d…...

uni-app附件下载预览 并解决打开附件时黑屏

// 预览附件perviewFile(file) {console.log(点击附件, file)var strfile.previewUrlvar filTypestr.split(.)console.log(filType,filType)uni.downloadFile({url: success: function(res) {console.log(打开文档成功, res);if (res.statusCode 200) {uni.saveFile({tempFile…...

卸载了Visual Studio后,在vscode中执行npm i或npm i --force时报错,该怎么解决?

卸载了Visual Studio后&#xff0c;在vscode中执行npm i或npm i --force时报错,该怎么解决&#xff1f; 报错内容&#xff1a;原因解决办法 报错内容&#xff1a; npm ERR! code 1 npm ERR! path E:\VScode\codeDate\yugan\node_modules\node-sass npm ERR! command failed np…...

渗透测试 | 信息收集常用方法合集

目录 一、关于域名 1.子域名收集 a.搜索引擎查找 b.在线查询 c.工具 d.SSL/TLS证书查询 2.端口型站点收集 3.目录文件扫描 a.目录扫描工具 b.github搜索 c.google搜索 d.在线网站 e.文件接口工具 4.旁站和C段 a.旁站查询 b.C段查询 5.网站技术架构信息 a.基础…...

使用 ElementUI 组件构建无边框 Window 桌面应用(WinForm/WPF)

生活不可能像你想象得那么好,但也不会像你想象得那么糟。 我觉得人的脆弱和坚强都超乎自己的想象。 有时,我可能脆弱得一句话就泪流满面;有时,也发现自己咬着牙走了很长的路。 ——莫泊桑 《一生》 一、技术栈 Vite + Vue3 + TS + ElementUI(plus) + .NET Framework 4.7.2…...

JavaScript中数组的方法和函数作用域问题

1 -函数作用域问题-: 函数的外层作用域&#xff0c;在函数创建时就已确定&#xff0c;和函数的调用位置无关 var name 嘿嘿;// 函数的外层作用域&#xff0c;在函数创建时就已确定&#xff0c;和函数的调用位置无关// JS中的作用域被称为 词法作用域function fn() {console.…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?

FTP&#xff08;File Transfer Protocol&#xff09;本身是一个基于 TCP 的协议&#xff0c;理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况&#xff0c;主要原因包括&#xff1a; ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...