【spring篇】CJLIB 动态代理

目录

什么是cjlib动态代理?

CGLIB的实现技术

 底层实现原理

CGLIB动态代理的实现原理:

 使用cjlib动态代理技术为什么要使用Enhancer对象

Intercept方法


与JDK动态代理对比着看,使更容易理解;

 

什么是cjlib动态代理?

CGLIB(Code Generation Library)是一种用于生成字节码并创建动态代理类的动态代理库。与JDK动态代理不同,CGLIB可以代理类而不仅仅是接口,因此更适用于那些没有实现接口的类。

CGLIB通过在运行时生成目标类的子类,并在子类中重写或增加方法来实现动态代理。这种方式与JDK动态代理使用接口的方式不同。在使用CGLIB动态代理时,生成的代理类是目标类的子类,而不是实现了某个接口的类。

总的来说,CGLIB是一种强大的动态代理技术,特别适用于那些无法或方便使用接口的情况。在面向切面编程(AOP)等场景中,CGLIB通常被用于生成代理类,以实现横切关注点的功能。

CGLIB的实现技术

在CGLIB中有两个重要的技术,Enhancer 和 MethodInterceptor ,它们在CGLIB动态代理中分别起到不同的作用:

  1. Enhancer:

    • 作用: 用于创建动态代理类。它负责配置和生成代理类的过程。
    • 功能:
      • 设置代理类的父类。
      • 指定回调对象,即处理方法调用的对象。
      • 设置过滤器,用于控制哪些方法需要被代理。
      • 生成代理类的实例。
  2. MethodInterceptor:

    • 作用: MethodInterceptor 接口定义了代理对象的拦截逻辑,用于在调用代理对象的方法时添加横切逻辑。
    • 功能:
      • 在 intercept 方法中实现代理逻辑,包括前置处理、调用目标方法、后置处理等。
      • 提供了 objmethodargsproxy 参数,用于获取被代理对象、被调用方法、方法参数和代理对象。

通过结合使用 Enhancer 和 MethodInterceptor,可以实现对目标对象的动态代理。Enhancer用于配置和生成代理类,而 MethodInterceptor 用于定义代理逻辑。以下是一个简单的示例:

public class MyInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable {// 前置处理逻辑System.out.println("Before invoking method: " + method.getName());// 调用目标方法Object result = proxy.invokeSuper(obj, args);// 后置处理逻辑System.out.println("After invoking method: " + method.getName());return result;}public static void main(String[] args) {// 使用Enhancer创建代理类Enhancer enhancer = new Enhancer();enhancer.setSuperclass(MyClass.class);enhancer.setCallback(new MyInterceptor());// 生成代理类的实例MyClass proxyInstance = (MyClass) enhancer.create();// 调用代理对象的方法proxyInstance.someMethod();}
}

在这个例子中,Enhancer 设置了被代理类的父类和回调对象,而 MyInterceptor 实现了具体的代理逻辑。最终,通过 Enhancer 创建的代理类实例可以在调用方法时触发 MyInterceptor 中定义的逻辑。


 底层实现原理

CGLIB(Code Generation Library)是一个用于生成字节码并创建动态代理类的开源库。它的主要特点是能够代理没有实现接口的类,与JDK动态代理不同,它是通过生成目标类的子类来实现代理的。

CGLIB动态代理的实现原理:

  1. 字节码生成: CGLIB使用ASM(Java字节码操作和分析框架)等工具,在运行时生成目标类的子类。这个子类继承自目标类,拥有目标类的所有非私有方法。

  2. 方法拦截: CGLIB生成的子类中,被代理类的方法会被重写。在重写的方法中,会插入代理逻辑,即通知(advice)。这样,在调用被代理类的方法时,实际上调用的是CGLIB生成的子类的方法,从而执行了代理逻辑。

  3. 目标对象引用: CGLIB生成的子类中通常包含一个指向目标对象的引用,以便在代理逻辑中能够调用目标对象的方法。

  4. 动态类加载: CGLIB生成的子类的字节码会在运行时通过类加载器动态加载到内存中,成为新的类。这个过程通常发生在目标类首次被代理时。

  5. 织入(Weaving): 生成的子类与目标对象关联的过程被称为织入。织入可以在编译时、类加载时或运行时进行。CGLIB通常采用运行时织入的方式,即在目标类被加载到内存后,通过生成的子类与目标对象关联。

总的来说,CGLIB通过生成目标类的子类,并在子类中插入代理逻辑,实现了对目标类的动态代理。这使得在运行时能够在目标方法的执行前后插入横切逻辑,从而实现面向切面编程的功能。

public static void main(String[] args) {// 使用Enhancer创建代理类Enhancer enhancer = new Enhancer();enhancer.setSuperclass(MyClass.class);enhancer.setCallback(new MyInterceptor());// 生成代理类的实例MyClass proxyInstance = (MyClass) enhancer.create();// 调用代理对象的方法proxyInstance.someMethod();}

 

 使用cjlib动态代理技术为什么要使用Enhancer对象

在CGLIB中,Enhancer 是一个用于创建动态代理类的关键类。使用 Enhancer 对象是为了配置和生成代理类的过程。以下是为什么要使用 Enhancer 对象的一些原因:

  1. 配置代理类: Enhancer 提供了一系列方法,可以用来配置代理类的行为,例如设置父类、指定回调(Callback)、设置过滤器(Filter)等。通过这些配置,可以定制生成的代理类的特性。

  2. 设置父类: 使用 Enhancer 可以指定生成的代理类的父类,这是CGLIB与JDK动态代理不同的地方。被代理类的方法会被继承到生成的代理类中,并可以在代理类中重写或增加方法

  3. 设置回调: Enhancer 允许设置回调对象,即用于处理方法调用的对象。回调通常是实现了 MethodInterceptor 接口的对象,它的 intercept 方法中包含了代理逻辑。

  4. 设置过滤器: 可以通过 Enhancer 设置过滤器来控制哪些方法需要被代理。过滤器是一个实现了 CallbackFilter 接口的对象,根据方法的索引返回相应的回调对象。

  5. 生成代理类实例: 通过 Enhancer 的 create 方法可以生成代理类的实例。这个实例可以用来调用被代理类的方法,并在方法调用前后执行代理逻辑。

Enhancer 被用来设置父类、回调对象,并最终生成代理类的实例。通过 MethodInterceptor 的实现,可以在代理逻辑中添加横切关注点。


Intercept方法

intercept 方法是 net.sf.cglib.proxy.MethodInterceptor 接口中定义的方法,用于定义代理对象的具体逻辑。该方法在调用代理对象的方法时被触发,允许在目标方法执行前后添加横切逻辑。

Object intercept(Object obj, java.lang.reflect.Method method,Object[] args, MethodProxy proxy) throws Throwable;

参数说明:

  • obj: 被代理对象的实例,即生成的代理类的实例

  • method: 被代理方法的反射对象,包含了被调用的方法的信息。

  • args: 被调用方法的参数数组

  • proxy: MethodProxy 对象,用于调用父类的方法或者调用其他代理方法

返回值:代理方法的返回值,类型为 Object

在 intercept 方法中,你可以编写代理逻辑,实现在目标方法执行前后进行一些操作。通常,你会在方法的开始部分添加一些前置处理逻辑,然后通过 proxy.invokeSuper(obj, args) 调用目标方法,最后在方法的结束部分添加一些后置处理逻辑

以下是一个简单的例子:

public class MyInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable {// 前置处理逻辑System.out.println("Before invoking method: " + method.getName());// 调用目标方法Object result = proxy.invokeSuper(obj, args);// 后置处理逻辑System.out.println("After invoking method: " + method.getName());return result;}

在这个例子中,intercept 方法实现了一个简单的前置处理和后置处理逻辑。你可以根据实际需求编写更复杂的代理逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/171937.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Sentry介绍与使用 - Issues模块

这篇文章是我在公司做 Sentry 相关分享的演讲稿。 大家好,现在由我来讲解 Sentry 的 Issues (问题)模块。我会分为三个部分来讲,首先我会介绍 Sentry 一些重要的概念,然后讲一下 Issues 的基本使用方式,最后…

steam/csgo搬砖项目真能月入过万吗?到底真的假的

steam/csgo搬砖第三课之如何出售 steam搬砖核心原理是什么?为什么会有差价产生?buff不是更低价吗?很多小白会有这些疑问! steam搬砖指的是通过买卖csgo游戏装备赚钱的。 玩过游戏的应该就很清楚,像绝地求生&#xff…

2023年第六届传智杯程序设计挑战赛(个人赛)B组 赛后复盘

传智杯赛后复盘 大家好 我是寸铁👊 2023年第六届传智杯程序设计挑战赛(个人赛)B组 赛后复盘 喜欢的小伙伴可以点点关注 💝 1. 字符串拼接 细节:一定要清楚nextLine()和next()的区别 nextLine()是遇到回车会停下来 nex…

Linux安装jdk8【十分丝滑】

1.上传安装包到Linux💕💕💕 2.使用命令解压缩💕💕💕 tar -zxvf 压缩文件名 3.重命名💕💕💕 mv 原文件名 新的文件名 4.配置环境变量🤩🤩&…

Linux中vi常用命令-批量替换

在日常服务器日志查看中常用到的命令有grep、tail等,有时想查看详细日志,用到vi命令,记录下来,方便查看。 操作文件:test.properites 一、查看与编辑 查看命令:vi 文件名 编辑命令:按键 i&…

CountDownLatch实战应用——批量数据多线程协调异步处理(主线程执行事务回滚)

😊 作者: 一恍过去 💖 主页: https://blog.csdn.net/zhuocailing3390 🎊 社区: Java技术栈交流 🎉 主题: CountDownLatch实战应用——批量数据多线程协调异步处理(主线程执行事务…

图像分割模型及架构选型介绍(MMSegmentation|sssegmentation等)

参考: https://zhuanlan.zhihu.com/p/618226513 0. 图像分割概述 图像分割通过给出图像中每个像素点的标签,将图像分割成若干带类别标签的区块,可以看作对每个像素进行分类。图像分割是图像处理的重要组成部分,也是难点之一。随…

C++如何实现自定义的struct作为unordered_set、unordered_map的key?

有两种方法&#xff1a; 1、自定义新struct的hash函数&#xff0c;和操作符&#xff0c;使用的时候需要指定unordered_set的第三个模板参数&#xff1a; #include <iostream> #include <unordered_map>struct MyStruct {std::string name;int id;// 自定义哈希函数…

OpenGL 自学总结

前言&#xff1a; 本人是工作后才接触到的OpenGL&#xff0c;大学找工作的时候其实比较着急&#xff0c;就想着尽快有个着落。工作后才发现自己的兴趣点。同时也能感觉到自己当前的工作有一点温水煮青蛙的意思&#xff0c;很担心自己往后能力跟不上年龄的增长。因此想在工作之余…

3DCAT为华东师大设计学院打造元宇宙数字虚拟学院

6月11日&#xff0c;华东师范大学设计学院在chi K11美术馆举办了一场别开生面的 2023 年本科毕业设计暨项目实践教学现场演示展。其中&#xff0c;元宇宙数字虚拟学院&#xff08;一期&#xff09;的现场发布会引起了现场震撼&#xff0c;吸引了众多观众的目光和参与。 该元宇宙…

MYSQL 连接的使用

文章目录 前言连接介绍在命令提示符中使用 INNER JOINMySQL LEFT JOINMySQL RIGHT JOIN在PHP脚本中使用JOIN后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;Mysql &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握…

【Windows】执行tasklist/taskkill提示“错误:找不到”或者“ERROR: not found”的解决方案

原因 由于WinMgmt异常导致起不来&#xff0c;而WinMgmt是SVCHOST进程中的WMI服务&#xff0c;解决这个问题需要停止之后再重新启动。 WinMgmt是Windows 2000客户端管理的核心组件&#xff0c;当客户端应用程序连接或当管理程序需要它本身的服务时&#xff0c;这个进程就会初始…

【挑战业余一周拿证】二、在云中计算 - 第 1 节 - 模块2 简介

第 1 节 - 模块2 简介 无论你的企业是属于像医疗、保健、制造、保险等等行业 , 再或者 , 您的服务是向全世界的数百万用户提供视频、、图片或者文字服务,你也需要服务器来为您的业务和应用程序提供支持,服务器的作用是帮助您托管应用程序并提供满足您业务需求的计算能力. 当你使…

XML Schema 的extension 元素

XML Schema 的extension 元素对complexContent、simpleContent元素进行扩展。 例如&#xff0c;下面通过增加了两个属性&#xff0c;对simpleContent进行了扩展&#xff1a; <xs:element name"condition" maxOccurs"unbounded" minOccurs"0"…

Vue框架学习笔记——计算属性

文章目录 前文提要代码需求描述插值语法实现methods实现 计算属性getter执行时间&#xff1a;setter 计算属性简写形式&#xff08;只读不改&#xff0c;才能如此简写&#xff09;slice截取元素&#xff0c;限制输入字符数量 前文提要 本人仅做个人学习记录&#xff0c;如有错…

Leetcode 2939. Maximum Xor Product

Leetcode 2939. Maximum Xor Product 1. 解题思路2. 代码实现3. 代码优化&#xff1a; 题目链接&#xff1a;2939. Maximum Xor Product 1. 解题思路 这一题思路上来说我们就是逐位进行考虑。 对于xor操作&#xff0c;显然我们只有以下两种情况&#xff1a; 00或者11&…

【brpc学习实践九】mbvar及bvar可观测

概念、学习地址 mbvar中有两个类&#xff0c;分别是MVariable和MultiDimension&#xff0c;MVariable是多维度统计的基类&#xff0c;MultiDimension是派生模板类。也是主要用来多多线程计数用的。这里用到再详细去了解即可 https://github.com/luozesong/brpc/blob/master/do…

知识的分层:know-what/how/why

知识&#xff08;knowledge&#xff09;表示知道某些信息。通常而言&#xff0c;知识是正确的&#xff0c;但不一定是完备的。知识本身有自己的适用范围&#xff0c;特别是工程技术类问题。 根据知识的类型&#xff0c;可分为三类&#xff1a; know-whatknow-howknow-why kno…

Java多线程二-线程安全

1、线程安全问题 多个线程&#xff0c;同时操作同一个共享资源的时候&#xff0c;可能会出现业务安全问题。 2、实例&#xff1a;取钱的线程安全问题 2.1、场景 小明和小红是夫妻&#xff0c;他们有个共同账户&#xff0c;余额是十万元&#xff0c;如果两人同时取钱并且各自取…

vue3-10

动态路由与菜单 路由文件 a6router.ts import { createRouter, createWebHashHistory } from "vue-router"; import { useStorage } from "vueuse/core"; import { Route, Menu } from "../model/Model8080"; const clientRoutes [{path: &q…