禅与计算机 禅与计算机
首页
  • Java基础

    • 一文搞懂Java核心技术
    • Java面向对象知识点大总结,建议收藏
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
    • Java异常:从原理到实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
    • 探索JVM的隐秘角落:元空间详解
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 元认知

    • 摩擦感:AI时代的写作自省
    • 从断墨寻径浅谈程序员的元学习能力
    • AI时代专注力培养
    • 如何阅读一本书:技术书籍的读书笔记方法论
  • 开发工具

    • IDEA配置详解与高效使用指南
    • Windows环境下JDK安装与环境变量配置
    • Windows 10 下的 Maven 安装配置教程
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • Elasticsearch核心原理与架构设计
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • 一文带你速通Go语言基础语法
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发的Go语言协程实践
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
    • 基于 Claude Code 复刻 Redis 慢查询指令实践
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • 从开源框架中学习那些实用的位运算技巧
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
  • AI工具链

    • Claude Code 实战指南:从安装配置到企业级开发流程
    • 一次 Claude Code 启动失败的 AI 辅助排查复盘
    • 基于提示词工程与KITE框架的Redis签到功能开发实践
    • Claude Code 记忆管理:CLAUDE.md 最佳实践
    • Claude Code 规则管理:Rules 拆分编排与迭代实践(文末送书)
    • VSCode与Claude Code后端开发环境搭建与AI编程工作流实践
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

sharkchili

计算机禅修者
首页
  • Java基础

    • 一文搞懂Java核心技术
    • Java面向对象知识点大总结,建议收藏
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
    • Java异常:从原理到实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
    • 探索JVM的隐秘角落:元空间详解
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 元认知

    • 摩擦感:AI时代的写作自省
    • 从断墨寻径浅谈程序员的元学习能力
    • AI时代专注力培养
    • 如何阅读一本书:技术书籍的读书笔记方法论
  • 开发工具

    • IDEA配置详解与高效使用指南
    • Windows环境下JDK安装与环境变量配置
    • Windows 10 下的 Maven 安装配置教程
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • Elasticsearch核心原理与架构设计
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • 一文带你速通Go语言基础语法
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发的Go语言协程实践
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
    • 基于 Claude Code 复刻 Redis 慢查询指令实践
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • 从开源框架中学习那些实用的位运算技巧
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
  • AI工具链

    • Claude Code 实战指南:从安装配置到企业级开发流程
    • 一次 Claude Code 启动失败的 AI 辅助排查复盘
    • 基于提示词工程与KITE框架的Redis签到功能开发实践
    • Claude Code 记忆管理:CLAUDE.md 最佳实践
    • Claude Code 规则管理:Rules 拆分编排与迭代实践(文末送书)
    • VSCode与Claude Code后端开发环境搭建与AI编程工作流实践
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java基础

  • 并发编程

  • JVM相关

  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
      • 写在文章开头
      • 详解Spring对AOP的设计与实现
        • 对AOP的理解
        • 什么是AOP中切点、切面、通知
        • Spring AOP和AspectJ AOP的区别
        • AspectJ 通知类型
        • 多个切面执行顺序我们如何确定
        • AOP操作在bean生命周期的那个阶段实现
        • 动态代理的基本概念
        • 动态代理的创建过程
      • 详解CGLIB代理
        • Spring AOP和Cglib的关系
        • Cglib代理流程是是什么样的
        • Spring中的Cglib代理流程
        • JDK代理示例
        • JDK代理的工作原理
        • Spring AOP中JDK代理的实现
      • 代理性能对比与Spring Boot选择
      • 小结
      • Spring AOP相关面试题精选
        • 1. 以下关于AOP的说法,正确的是?
      • 参考
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 深入解读 Spring MVC:Web 开发的得力助手
    • 探索 Spring 事务的奥秘
    • 来聊聊事务监听
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 深入剖析源码速通Spring多数据源问题
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于sharding-jdbc拓展点实现复杂分库分表算法
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
    • 一文快速掌握高性能内存队列Disruptor
    • 安利一个轻量级流程引擎compileflow
    • 来聊聊一个轻量级的有限状态机Cola-StateMachine
  • Java核心技术
  • 深入理解Spring框架
sharkchili
2026-03-24
目录

Spring AOP 深度剖析与实践

# 写在文章开头

我们日常用AOP解耦业务与非业务功能的关系,但你是否真正了解过以下几个问题:

  • Spring AOP是如何实现方法拦截的?
  • JDK动态代理和CGLIB代理有什么区别?性能差异大吗?
  • 为什么Spring Boot 2.x默认选择CGLIB代理?

本文将从源码层面深入剖析Spring AOP的实现原理,并通过性能测试代码验证JDK动态代理与CGLIB的真实性能差异,让你真正从设计理念上了解AOP 并能够正确的应用这项技术。

你好,我是 SharkChili ,Java Guide 核心维护者之一,对 Redis、Nightingale 等知名开源项目有深度源码研究经验。熟悉 Java、Go、C 等多语言技术栈,现任某知名黑厂高级开发工程师,专注于高并发系统架构设计与性能优化。

🌟 开源项目贡献

  • mini-redis:教学级 Redis 精简实现,助力分布式缓存原理学习
    🔗 https://github.com/shark-ctrl/mini-redis (opens new window)(欢迎 Star & Contribute)

📚 公众号价值 分享企业级架构设计、性能优化、源码解析等核心技术干货,涵盖分布式系统、微服务治理、大数据处理等实战领域,并探索面向AI的vibe coding等现代开发范式。

👥 加入技术社群 关注公众号,回复 【加群】 获取联系方式,与众多技术爱好者交流分布式架构、微服务等前沿技术!

# 详解Spring对AOP的设计与实现

# 对AOP的理解

AOP(Aspect-Oriented Programming:面向切面编程),一种将业务与非业务职责分离的设计理念,通过降低彼此间的耦合度,确保各个模块间能够专注于各自的职责,降低后期开发维护和迭代的成本,AOP常见应用场景为:

  • 权限校验
  • 日志管理
  • 事务处理

由于语言的特性,Spring则是采用动态代理完成逻辑增强,在Spring 4.x及之前的的版本,如果被代理的类有实现接口的话,就会基于JDK Proxy完成代理的创建,反之就是通过Cglib完成代理创建,当然你也可以强制使用Cglib。

注:从Spring 5.x开始(也就是Spring Boot 2.x ),配置项proxy-target-class 默认值为 true,这意味着除非目标类是接口类型,默认情况下都使用 CGLIB 完成动态代理创建。

AOP代理模式示意图

# 什么是AOP中切点、切面、通知

AOP中有很多核心术语,分别是:

  1. 目标(Target): 这就被代理的对象,例如我们希望对UserService每个方法进行增强(在不动它的代码情况下增加一些非业务的动作),那么这个UserService就是目标。
  2. 代理(Proxy): 就是给你被代理后的对象的厂商,例如我们上面说过希望对UserService每个方法进行增强,那么给用户返回增强后的对象的类就是代理类。
  3. 连接点(JoinPoint):目标对象,每一个可能可以被增强的方法都可以称为连接点,尽管它最后可能不会被增强。
  4. 切入点(Pointcut): 定义"哪些连接点需要被增强"的表达式,通过表达式(如execution(* com.xxx.Service.*(..)))筛选匹配的连接点。
  5. 通知(Advice): 不要被表面的语义误导,通知并不是告知某人的意思,通知的意思是拦截对象后,做的增强操作,也就是拦截后要执行什么代码。
  6. 切面(Aspect): 切入点(Pointcut)+通知(Advice)。
  7. 织入(Weaving):把通知的动作融入到对象中,生成代理对象的过程就叫做织入。

AOP核心概念示意图

# Spring AOP和AspectJ AOP的区别

Spring AOP属于运行时增强,基于代理(Proxying)实现的。而AspectJ AOP属于编译时增强,基于字节码操作(Bytecode Manipulation)实现的。

# AspectJ 通知类型

  1. Before(前置通知): 目标对象方法调用前触发增强。
  2. After(后置通知/最终通知): 目标对象方法调用后进行增强,无论方法正常返回还是抛出异常都会执行(类似finally块)。
  3. AfterReturning(返回通知):目标对象方法执行结束,返回值时进行增强。
  4. AfterThrowing(异常通知):目标对象方法执行报错并抛出时做的增强。
  5. Around(环绕通知):这个比较常用了,目标对象方法调用前后我们可以做各种增强操作,甚至不调用对象的方法都能做到。

# 多个切面执行顺序我们如何确定

有两种方式: 第一种: 使用@Order注解来决定切面bean的执行顺序。

// 值越小优先级越高
@Order(1)
@Component
@Aspect
public class LoggingAspect implements Ordered {

1
2
3
4
5
6

第二种: 继承接口法,实现implements Ordered接口显示声明序号:

@Component
@Aspect
public class LoggingAspect implements Ordered {

    // ....

    @Override
    public int getOrder() {
        // 返回值越小优先级越高
        return 1;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13

# AOP操作在bean生命周期的那个阶段实现

AOP动态增强在bean初始化前后 即BeanPostProcessor接口实现(也就是业内常说的BPP阶段)完成动态代理创建:

对应源码位于AbstractAutoProxyCreator的postProcessAfterInitialization方法完成,这里我们看到代码中一个earlyProxyReferences的remove操作,实际上这是为了避免互相依赖的bean重复增强问题。

@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {// 若返回null,则说明被增强的bean没有提前暴露,调用wrapIfNecessary执行增强
				return wrapIfNecessary(bean, beanName, cacheKey);//创建代理
			}
		}
		return bean;
	}
1
2
3
4
5
6
7
8
9
10

对此我们可以分为两个场景讨论,

  • 假设我创建a对象,没有任何依赖关系,那么下面这段方法返回的就是null,直接完成增强返回。
  • 又假设我们需要创建a、b两个对象,且这两个对象互相依赖,按照Spring的创建流程则如下
1. 创建 A(实例化)
      ↓
2. 属性填充发现依赖 B
      ↓
3. 创建 B(实例化)
      ↓
4. B 属性填充发现依赖 A
      ↓
5. 调用 getEarlyBeanReference(A)
   - 将 A 存入 earlyProxyReferences
   - 对 A 进行代理增强
      ↓
6. B 获得增强后的 A,B 创建完成
      ↓
7. A 继续初始化,执行 postProcessAfterInitialization
   - 发现 earlyProxyReferences 中有自己
   - 说明之前已增强,直接返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 动态代理的基本概念

是在运行期间,创建目标对象的代理对象,目标对象不变,我们通过对目标方法进行动态拦截,在代理方法前后执行各种增强逻辑操作。

# 动态代理的创建过程

我们以最新版的Spring 5.x为例,对应动态创建创建的代码位于DefaultAopProxyFactory核心方法createAopProxy,核心逻辑为:

  1. 判断isProxyTargetClass(默认为true,2.x版本默认配置)是否为true,若不为true则通过jdk动态代理完成创建,反之进入步骤2
  2. 判断是否是接口,如果是接口也通过JDK动态创建完成创建(典型实现为mybatis mapper),反之进入步骤3
  3. 所有默认情况都执行ObjenesisCglibAopProxy通过CGLIB完成动态增强
@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		// Spring 5.x isProxyTargetClass返回true,默认情况下都会强制走cglib
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			Class<?> targetClass = config.getTargetClass();
			//如果是接口则走JdkDynamicAopProxy反之走ObjenesisCglibAopProxy
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

对应我们也给出jdk动态代理的创建细节,本质上就是通过反射完成创建:

@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		.........
	//获取被代理的类的接口
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);

		//生成代理对象并返回
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}
1
2
3
4
5
6
7
8
9
10

而cglib实现也很预期说明的一致,通过ASM完成字节码增强:

@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
	.......
		try {
		.......
		//将当前类信息通过enhancer 生成代理对象
			Enhancer enhancer = createEnhancer();
			if (classLoader != null) {
				enhancer.setClassLoader(classLoader);
				if (classLoader instanceof SmartClassLoader &&
						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
					enhancer.setUseCache(false);
				}
			}
			//设置目标类元信息
			enhancer.setSuperclass(proxySuperClass);
			enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
			enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));

			Callback[] callbacks = getCallbacks(rootClass);
			Class<?>[] types = new Class<?>[callbacks.length];
			for (int x = 0; x < types.length; x++) {
				types[x] = callbacks[x].getClass();
			}
		//返回最终生成的代理对象
			return createProxyClassAndInstance(enhancer, callbacks);
		}
		........
		}
		catch (Throwable ex) {
		......
		}
	}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 详解CGLIB代理

# Spring AOP和Cglib的关系

CGLIB是一个强大、高性能的代码生成包。使用ASM操作字节码,动态生成代理,对方法进行增强。,它广泛的被许多AOP框架使用,为他们提供方法的拦截。

CGLIB代理原理示意图

例如我们希望对某个service进行日志打印,基于CGLIB我们可以这样实现:

前置步骤引入依赖:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>
1
2
3
4
5

首先创建用户类

public class User {
    private String name;

    private int age;

  	//get set


   
}

1
2
3
4
5
6
7
8
9
10
11

对应我们也给出一个serivice类的代码示例,即通过一个简单的死数据完成列表查询操作:

public class UserServiceImpl {

    public List<User> findUserList() {
        return Collections.singletonList(new User("xiaoming", 18));
    }
}

1
2
3
4
5
6
7

对应代理实现逻辑如下:

public class CglibProxy<T> implements MethodInterceptor {


    private static Logger logger = LoggerFactory.getLogger(CglibProxy.class);

    private Object target;


    public  T getTargetClass(Object target) {
        //设置被代理的目标类
        this.target = target;
        // 创建加强器设置代理类以及回调,当代理类被调用时,callback就会去调用intercept
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        //返回代理类
        return (T) enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        logger.info("调用被代理对象的方法,代理对象:[{}],代理方法:[{}]", o.getClass().getName(), method.getName());
        Object result = methodProxy.invokeSuper(o, args);
        logger.info("代理调用结束,返回结果:[{}]", String.valueOf(result));

        return result;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

测试代码

public class Main {
    public static void main(String[] args) {
        CglibProxy<UserServiceImpl> cglibProxy = new CglibProxy();

        UserServiceImpl targetClass =cglibProxy.getTargetClass(new UserServiceImpl());
        targetClass.findUserList();

    }
}

1
2
3
4
5
6
7
8
9
10

# Cglib代理流程是是什么样的

如下图所示,整体来说就是基于enhancer去配置被代理类的各种参数,然后生成代理类:

注意:final方法无法被代理,因为它不可被子类覆盖。

CGLIB代理创建流程图

# Spring中的Cglib代理流程

源码如下,我们可以看出和我们写的实例代码是差不多的。

@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
.....

		try {
			//获取当前类信息获取生成代理对象
			Enhancer enhancer = createEnhancer();
			if (classLoader != null) {
				enhancer.setClassLoader(classLoader);
				if (classLoader instanceof SmartClassLoader &&
						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
					enhancer.setUseCache(false);
				}
			}
			enhancer.setSuperclass(proxySuperClass);
			enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
			enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));

		// 获取当前类中的方法
			Callback[] callbacks = getCallbacks(rootClass);
			Class<?>[] types = new Class<?>[callbacks.length];
			for (int x = 0; x < types.length; x++) {
				types[x] = callbacks[x].getClass();
			}
			
			enhancer.setCallbackFilter(new ProxyCallbackFilter(
					this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
			enhancer.setCallbackTypes(types);

			// 生成代理对象
			return createProxyClassAndInstance(enhancer, callbacks);
		}
		catch (CodeGenerationException | IllegalArgumentException ex) {
			.....
		}
		catch (Throwable ex) {
			.....
		}
	}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# JDK代理示例

JDK动态代理是JDK自带的一种代理机制,我们只需实现InvocationHandler接口即可。但是前提是被代理的类必须实现一个或多个接口才能使用JDK动态代理。

首先我们定义接口,User类沿用上述的

public interface UserService {

    List<User> findUserList();
}

1
2
3
4
5

修改UserServiceImpl

public class UserServiceImpl implements UserService{

    @Override
    public List<User> findUserList() {
        return Collections.singletonList(new User("xiaoming", 18));
    }
}

1
2
3
4
5
6
7
8

jdk代理类

public class JDKProxy<T> {

    private static Logger logger = LoggerFactory.getLogger(JDKProxy.class);

    private Object target;

    public JDKProxy(Object target) {
        this.target = target;
    }


    public T getTargetObj() {
        UserService proxy;
        ClassLoader loader = target.getClass().getClassLoader();
        Class[] interfaces = new Class[]{UserService.class};
        InvocationHandler handler = (p, method, args) -> {
            logger.info("代理方法被调用,类名称[{}],方法名称[{}]", target.getClass().getName(), method.getName());
            Object result = method.invoke(target, args);
            logger.info("代理方法调用结束,返回结果:[{}]", String.valueOf(result));
            return result;
        };

        proxy = (UserService) Proxy.newProxyInstance(loader, interfaces, handler);
        return (T) proxy;
    }


}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

测试代码

public class Main {
    public static void main(String[] args) {
       
        JDKProxy<UserService> jdkProxy=new JDKProxy<>(new UserServiceImpl());
        UserService userService = jdkProxy.getTargetObj();
        System.out.println(userService.findUserList());
    }
}

1
2
3
4
5
6
7
8
9

# JDK代理的工作原理

本质上,JDK动态代理也是在运行时定位获取目标,针对目标方法字节码逻辑前后写入增强逻辑,对外暴露代理调用,以我们上述findUserList为例,JDK代理会在运行时拦截该方法并将逻辑写入到字节码文件中,对外暴露一个代理的findUserList调用:

我们不妨在jvm在下面这样一段参数,将saveGeneratedFiles设置为 true 后,让生成的代理类会被保存到项目根目录,看看JDK代理在这期间做了什么事情:

 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
1

调试运行后,可以发现它回步入generateProxyClass方法,从语义我们大体可以猜测,它执行了:

  • 创建代理
  • 动态修改字节码
public static byte[] generateProxyClass(final String name,
                                        Class<?>[] interfaces,
                                        int accessFlags)
{
    ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
    final byte[] classFile = gen.generateClassFile();
    ...
}

1
2
3
4
5
6
7
8
9

而代理方法做的事情,整体如下所示,可以看到它整体做的就是拿着被代理类的各种方法封装成ProxyMethod方法,然后写入class文件中:

/**
    * Generate a class file for the proxy class.  This method drives the
    * class file generation process.
    */
private byte[] generateClassFile() {

    /* 第一步:将所有方法包装成ProxyMethod对象 */
    
    // 将Object类中hashCode、equals、toString方法包装成ProxyMethod对象
    addProxyMethod(hashCodeMethod, Object.class);
    addProxyMethod(equalsMethod, Object.class);
    addProxyMethod(toStringMethod, Object.class);

    // 将代理类接口方法包装成ProxyMethod对象
    for (Class<?> intf : interfaces) {
        for (Method m : intf.getMethods()) {
            addProxyMethod(m, intf);
        }
    }

   	//......

    /* 第二步:为代理类组装字段,构造函数,方法,static初始化块等 */
    try {
        // 添加构造函数,参数是InvocationHandler
        methods.add(generateConstructor());

        // 代理方法
        for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
            for (ProxyMethod pm : sigmethods) {

                // 字段
                fields.add(new FieldInfo(pm.methodFieldName,
                    "Ljava/lang/reflect/Method;",
                        ACC_PRIVATE | ACC_STATIC));

                // 上述ProxyMethod中的方法
                methods.add(pm.generateMethod());
            }
        }

        // static初始化块
        methods.add(generateStaticInitializer());

    } catch (IOException e) {
        throw new InternalError("unexpected I/O Exception", e);
    }
	//......

    /* 第三步:写入class文件 */

  	//......

    try {
  			//......
        dout.writeShort(0); // (no ClassFile attributes for proxy classes)

    } catch (IOException e) {
        throw new InternalError("unexpected I/O Exception", e);
    }

    return bout.toByteArray();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

看看上文命令下创建class,可以看到它 implements UserService 以及通过我们的的代理类的InvocationHandler 调用这些方法

public final class $Proxy0 extends Proxy implements UserService {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

   	//......
   	
	//动态代理了findUserList方法,后续调用时本质上是通过代理类的method对原有方法进行调用,即我们的InvocationHandler所实现的逻辑
    public final List findUserList() throws  {
        try {
            return (List)super.h.invoke(this, m3, (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"));
            //初始化我们的代理方法类method
            m3 = Class.forName("com.pdai.aop.jdkProxy.UserService").getMethod("findUserList");
            	//......
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# Spring AOP中JDK代理的实现

JdkDynamicAopProxy源码如下,可以看到本质上也是通过传入:

  1. 类加载器
  2. 接口类型,通过proxiedInterfaces获取对应接口到代理缓存中获取要生成的代理类型
  3. 对应的InvocationHandler 进行逻辑增强。
@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
	
	//......
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}
1
2
3
4
5
6

# 代理性能对比与Spring Boot选择

在JDK8之前,CGLIB代理的方法调用效率确实优于JDK动态代理,但JDK动态代理的代理创建效率更高(参考《精通Spring4.x》一书及相关性能测试文章 (opens new window))。

JDK动态代理与CGLIB性能对比

从JDK8开始,JIT编译器对反射调用进行了大量优化(如内联优化),JDK动态代理的方法调用效率已与CGLIB相当。

以下是性能对比测试核心代码:

/**
 * JDK动态代理 vs CGLIB代理 性能对比测试
 */
public class ProxyPerformanceTest {

    private static final int CREATE_ITERATIONS = 100_000;  // 代理创建次数
    private static final int INVOKE_ITERATIONS = 10_000_000; // 方法调用次数

    // 目标接口
    public interface UserService {
        String getUserName(Long userId);
    }

    // 目标实现类
    public static class UserServiceImpl implements UserService {
        @Override
        public String getUserName(Long userId) {
            return "User_" + userId;
        }
    }

    // JDK动态代理的InvocationHandler
    public static class JdkProxyHandler implements InvocationHandler {
        private final Object target;
        public JdkProxyHandler(Object target) { this.target = target; }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return method.invoke(target, args);
        }
    }

    // CGLIB的MethodInterceptor
    public static class CglibProxyInterceptor implements MethodInterceptor {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            return proxy.invokeSuper(obj, args);
        }
    }

    // 测试代理创建效率
    private static void testProxyCreation() {
        UserServiceImpl target = new UserServiceImpl();

        // JDK动态代理创建
        long jdkStart = System.nanoTime();
        for (int i = 0; i < CREATE_ITERATIONS; i++) {
            UserService jdkProxy = (UserService) Proxy.newProxyInstance(
                UserService.class.getClassLoader(),
                new Class<?>[]{UserService.class},
                new JdkProxyHandler(target)
            );
        }
        long jdkDuration = System.nanoTime() - jdkStart;

        // CGLIB代理创建
        long cglibStart = System.nanoTime();
        for (int i = 0; i < CREATE_ITERATIONS; i++) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(UserServiceImpl.class);
            enhancer.setCallback(new CglibProxyInterceptor());
            enhancer.create();
        }
        long cglibDuration = System.nanoTime() - cglibStart;

        System.out.printf("JDK动态代理创建耗时: %,d ms%n", TimeUnit.NANOSECONDS.toMillis(jdkDuration));
        System.out.printf("CGLIB代理创建耗时:   %,d ms%n", TimeUnit.NANOSECONDS.toMillis(cglibDuration));
    }

    // 测试方法调用效率
    private static void testMethodInvocation() {
        UserServiceImpl target = new UserServiceImpl();
        UserService jdkProxy = (UserService) Proxy.newProxyInstance(
            UserService.class.getClassLoader(),
            new Class<?>[]{UserService.class},
            new JdkProxyHandler(target)
        );

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserServiceImpl.class);
        enhancer.setCallback(new CglibProxyInterceptor());
        UserService cglibProxy = (UserService) enhancer.create();

        // JDK代理方法调用
        long jdkStart = System.nanoTime();
        for (int i = 0; i < INVOKE_ITERATIONS; i++) {
            jdkProxy.getUserName((long) i);
        }
        long jdkDuration = System.nanoTime() - jdkStart;

        // CGLIB代理方法调用
        long cglibStart = System.nanoTime();
        for (int i = 0; i < INVOKE_ITERATIONS; i++) {
            cglibProxy.getUserName((long) i);
        }
        long cglibDuration = System.nanoTime() - cglibStart;

        System.out.printf("JDK动态代理调用耗时: %,d ms%n", TimeUnit.NANOSECONDS.toMillis(jdkDuration));
        System.out.printf("CGLIB代理调用耗时:   %,d ms%n", TimeUnit.NANOSECONDS.toMillis(cglibDuration));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

测试结果(JDK 17环境):

【测试1】代理创建效率对比 (100000 次)
JDK动态代理创建耗时:  40 ms (0.000 ms/个)
CGLIB代理创建耗时:    39 ms (0.000 ms/个)
创建效率对比: JDK 0.98倍 慢于 CGLIB
1
2
3
4

从测试结果可以看到,在JDK8+环境中,JIT编译器通过方法内联优化(将反射调用优化为直接方法调用)后,JDK动态代理和CGLIB在代理创建效率上差异已经非常小,几乎可以忽略不计。

再来看方法调用效率的测试结果:

【测试2】方法调用效率对比 (10000000 次)
直接调用耗时:         85 ms
JDK动态代理调用耗时:  404 ms
CGLIB代理调用耗时:    311 ms
方法调用效率对比: JDK 0.77倍 慢于 CGLIB
相对于直接调用的开销: JDK 4.71倍, CGLIB 3.63倍
1
2
3
4
5
6

从测试结果可以看到,CGLIB在方法调用效率上仍然略高于JDK动态代理(约快23%),这也是Spring Boot 2.x选择CGLIB作为默认代理的原因之一,当然更重要的原因还是CGLIB不强制要求类实现接口,避免了类型转换异常问题。

以下是Spring Boot 2.x中AopAutoConfiguration的源码,印证了上述结论:

@AutoConfiguration
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(Advice.class)
	static class AspectJAutoProxyingConfiguration {

		// JDK动态代理配置:需要显式设置 spring.aop.proxy-target-class=false
		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
		static class JdkDynamicAutoProxyConfiguration {

		}

		// CGLIB代理配置:默认生效(matchIfMissing = true)
		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)  // 关键:没有配置时默认使用CGLIB
		static class CglibAutoProxyConfiguration {

		}

	}

	// 当没有AspectJ依赖时,也默认使用CGLIB
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
			matchIfMissing = true)
	static class ClassProxyingConfiguration {

		@Bean
		static BeanFactoryPostProcessor forceAutoProxyCreatorToUseClassProxying() {
			return (beanFactory) -> {
				if (beanFactory instanceof BeanDefinitionRegistry) {
					BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
					AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
				}
			};
		}

	}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

从源码可以看到:

  1. CglibAutoProxyConfiguration中的matchIfMissing = true表示没有配置时默认使用CGLIB
  2. JdkDynamicAutoProxyConfiguration需要显式设置spring.aop.proxy-target-class=false才会生效

# 小结

本文从源码层面深入剖析了Spring AOP的实现原理,核心要点如下:

  1. Spring AOP基于动态代理实现:目标类实现接口时使用JDK动态代理,否则使用CGLIB
  2. JDK8+性能优化:JIT编译器通过方法内联优化,使JDK动态代理与CGLIB性能差距缩小
  3. Spring Boot 2.x默认CGLIB:主因是不强制要求类实现接口,避免类型转换异常,而非单纯性能考量
  4. 五种通知类型:Before、After、AfterReturning、AfterThrowing、Around,各有适用场景

希望本文能帮助你不仅会用Spring AOP,更能理解其底层原理。


你好,我是 SharkChili ,Java Guide 核心维护者之一,对 Redis、Nightingale 等知名开源项目有深度源码研究经验。熟悉 Java、Go、C 等多语言技术栈,现任某知名黑厂高级开发工程师,专注于高并发系统架构设计与性能优化。

🌟 开源项目贡献

  • mini-redis:教学级 Redis 精简实现,助力分布式缓存原理学习
    🔗 https://github.com/shark-ctrl/mini-redis (opens new window)(欢迎 Star & Contribute)

📚 公众号价值 分享企业级架构设计、性能优化、源码解析等核心技术干货,涵盖分布式系统、微服务治理、大数据处理等实战领域,并探索面向AI的vibe coding等现代开发范式。

👥 加入技术社群 关注公众号,回复 【加群】 获取联系方式,与众多技术爱好者交流分布式架构、微服务等前沿技术!

# Spring AOP相关面试题精选

# 1. 以下关于AOP的说法,正确的是?

A. AspectJ是编译时织入,可以织入任何方法

B. Spring AOP基于代理模式,只能代理public方法

C. JDK动态代理要求目标类实现接口

D. CGLIB通过接口实现代理

正确答案:C

解析:

A ❌:AspectJ是编译时/类加载时织入,不是Spring AOP的方式

B ❌:Spring AOP只能代理public方法(表述有歧义,但不够准确)

C ✅:JDK动态代理要求目标类实现接口,通过反射创建代理

D ❌:CGLIB通过继承实现代理(子类化),不是接口


# 参考

Spring 常见面试题总结:https://javaguide.cn/system-design/framework/spring/spring-knowledge-and-questions-summary.html#spring-基础 (opens new window)

Spring进阶 - Spring AOP实现原理详解之AOP切面的实现:https://www.pdai.tech/md/spring/spring-x-framework-aop-source-1.html (opens new window)

Spring进阶 - Spring AOP实现原理详解之AOP代理的创建:https://www.pdai.tech/md/spring/spring-x-framework-aop-source-2.html (opens new window)

Spring进阶 - Spring AOP实现原理详解之Cglib代理实现:https://www.pdai.tech/md/spring/spring-x-framework-aop-source-3.html (opens new window)

Spring进阶 - Spring AOP实现原理详解之JDK代理实现:https://www.pdai.tech/md/spring/spring-x-framework-aop-source-4.html (opens new window)

《spring实战第四版》

编辑 (opens new window)
#Spring#AOP#JDK动态代理#CGLIB代理#源码解析
上次更新: 2026/04/01, 11:24:40
Spring核心功能IOC详解
Spring 三级缓存机制深度解析

← Spring核心功能IOC详解 Spring 三级缓存机制深度解析→

最近更新
01
Windows 10 下的 Maven 安装配置教程
05-11
02
基于 Claude Code 复刻 Redis 慢查询指令实践
05-11
03
VSCode与Claude Code后端开发环境搭建与AI编程工作流实践
05-09
更多文章>
Theme by Vdoing | Copyright © 2025-2026 Evan Xu | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×
×