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

【Spring底层分析】AOP的cligb代理和jdk代理

AOP的cligb代理和jdk代理

spring默认创建的是clibg代理对象,如果想要让spring创建jdk代理对象,那么需要:

1、确保目标类实现至少一个接口

2、配置Spring强制使用JDK代理,@EnableAspectJAutoProxy(proxyTargetClass = false)

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false) // 关键设置
public class AppConfig {// 配置类内容
}

cligb代理对象代理流程:

  1. Spring为某些Bean创建CGLIB代理对象
  2. 调用方法时实际调用代理对象的方法
  3. 代理对象执行intercept()方法
  4. 生成拦截器链(由多个MethodInterceptor组成)
  5. 链执行器按顺序执行拦截器链中的每个拦截器的invoke方法,实际就是调用增强方法。
  6. 在合适的时机调用原始目标方法

无论是创建CGLIB代理对象、还是执行intercept()方法,实际上都是CglibAopProxy类里的方法。

class CglibAopProxy implements AopProxy, Serializable{public Object getProxy() {}public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//这里可以具体看我的另一篇文章,有详细介绍源码:https://blog.csdn.net/m0_73866527/article/details/148384920?spm=1001.2014.3001.5501}
}

jdk代理对象代理流程:

  1. Spring为某些Bean创建jdk代理对象
  2. 调用方法时实际调用代理对象的方法
  3. 代理对象执行invoke()方法
  4. 生成拦截器链(由多个MethodInterceptor组成)
  5. 链执行器按顺序执行拦截器链中的每个拦截器的invoke方法,实际就是调用增强方法。
  6. 在合适的时机调用原始目标方法

无论是创建CGLIB代理对象、还是执行intercept()方法,实际上都是JdkDynamicAopProxy类里的方法。

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler {public Object getProxy() {return getProxy(ClassUtils.getDefaultClassLoader());}public Object getProxy(@Nullable ClassLoader classLoader) {// 1. 获取目标接口Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);// 2. 关键:创建JDK代理实例return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);}// 实现InvocationHandler接口public Object invoke(Object proxy, Method method, Object[] args) {// 拦截逻辑// 获取目标对象(原始Bean)Target target = getTarget();// 创建拦截器链 - 与你熟悉的CGLIB完全一致!List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// 创建方法调用链执行器MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// 执行拦截器链 - 核心流程与你已知的CGLIB完全一致return invocation.proceed();}
}

在这里插入图片描述

在这里插入图片描述

这时候你肯定有疑惑,为什么代理对象执行目标方法时,会自动执行intercept方法或invoke方法?

在对象创建时通过字节码生成技术,将调用路径"刻印"在代理对象的DNA中,使得后续所有方法调用都能自动路由到正确的处理逻辑!

(这里留个坑,先不细挖了)

那么你又会有疑惑,为什么这两个代理方式差不多,为什么还需要有这两种代理方式呢?

维度JDK动态代理CGLIB代理差异影响
代理机制接口代理(实现相同接口)子类代理(继承目标类)根本设计哲学不同
目标要求必须实现接口类不能是final适用场景分化
性能特点创建快(≈15ns),调用慢(反射开销)创建慢(≈200ns),调用快(直接调用)高频调用场景选择关键
方法覆盖只能代理接口方法可代理所有非final方法功能覆盖范围不同
内存占用轻量级(约256字节)重量级(约1-2KB)资源敏感系统选择依据

- JDK代理是通过反射调用目标方法(因为代理对象和目标对象没有继承关系,只有共同的接口,所以只能反射调用目标对象的方法)。

- CGLIB代理是通过直接调用(通过方法索引,类似直接调用)父类(目标类)的方法(因为代理对象是目标对象的子类,所以可以调用父类方法)。

  • JDK代理 = "翻译官"模式
    • 需要懂双方语言(接口)
    • 每次沟通都要翻译(反射)
    • 适合临时简单任务
  • CGLIB代理 = "机械臂"模式
    • 直接嵌入操作环境(继承)
    • 预设精确操作指令(直接调用)
    • 适合高频重复任务
http://www.lqws.cn/news/510517.html

相关文章:

  • go语言 *和
  • 基于StarRocks的指标平台查询加速方案
  • sqlserver怎样动态执行存储过程,并且返回报错
  • 解决ptmalloc2内存过大的三种方案
  • 使用GDB调试程序方法
  • 02-Linux内核源码编译
  • java语言中的XML解析
  • 解决Fedora21下无法使用NWJS网页透明效果的问题
  • mybatisPlus动态表前缀
  • 磁悬浮轴承遇上“热浪”挑战:多参数自适应补偿策略揭秘
  • [学习] C语言编程中线程安全的实现方法(示例)
  • day041-web集群架构搭建
  • 棋盘格标定板和圆形标定板的优劣性
  • windows 上 build 时,微软给出的 vcpkg 工具,如何使用
  • MySQL 8.x配置MGR高可用+ProxySQL读写分离(三):配置ProxySQL主从分组信息
  • [3D-Portfolio] docs | js集中式配置 | React组件 | 组件嵌套
  • [附源码+数据库+毕业论文]基于Spring+MyBatis+MySQL+Maven+jsp实现的超市库存商品管理系统,推荐!
  • 16、nrf52840蓝牙学习(唯一ID加密与解密)
  • 华为认证预约考试、考试时长、取消/改期、补考时间汇总
  • C++ <vector>
  • Redis 乱码和LocalDateTime类型缓存问题
  • 鸿蒙开发深入解析:Data Ability 数据共享机制全面指南
  • 工业弧焊机器人气保焊节气装置
  • 搭建智能问答系统,有哪些解决方案,比如使用Dify,LangChain4j+RAG等
  • 【Altium】原理图位号自动标注
  • spring中的切面类实践
  • WPF CommunityToolkit.Mvvm
  • 【技术难题】el-table的全局数据排序实现示例,不受分页影响,以及异步请求带来的页面渲染问题
  • 针对基于深度学习的侧信道分析(DLSCA)进行超参数的贝叶斯优化
  • VIVADO导出仿真数据到MATLAB中进行分析