禅与计算机 禅与计算机
首页
  • 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最佳方案
    • 从开源框架中学习那些实用的位运算技巧
    • 对账核销场景设计与重构实践
    • 千万级交易流水慢查询综合治理实践
    • 记一次StarRocks源码级排错和既有架构优化实践
  • 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最佳方案
    • 从开源框架中学习那些实用的位运算技巧
    • 对账核销场景设计与重构实践
    • 千万级交易流水慢查询综合治理实践
    • 记一次StarRocks源码级排错和既有架构优化实践
  • 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核心知识点
        • 一、Spring 基础认知
        • 聊聊对Spring的理解
        • Spring包含那些模块
        • Spring,Spring MVC,Spring Boot 之间的关系
        • 如何根据配置动态生成 Spring 的 Bean
        • Spring 中注入 Bean 有几种方式
        • 二、IoC 与 DI
        • 谈谈你对IoC的理解
        • 介绍一下Spring的AOP
        • 知道什么是Spring bean吗?
        • 将一个类声明为 Bean 的注解有哪些?
        • @Component 和 @Bean 的区别是什么?
        • 通过注解注入 Bean 的方式有哪些
        • @Autowired 和 @Resource 的区别是什么
        • Bean 的作用域有哪些
        • BeanFactory 和 FactoryBean 的关系
        • 单例 Bean 的线程安全问题
        • Spring Bean 的生命周期
        • Spring默认支持循环依赖吗?如果发生如何解决
        • 三、Bean 生命周期与循环依赖
        • Spring是如何销毁bean的
        • 为什么Spring不建议使用基于字段的依赖注入
        • @PostConstruct、init-method和afterPropertiesSet执行顺序
        • Spring中shutdownhook作用是什么
        • 四、AOP 与事务
        • Spring的AOP在什么场景下会失效
      • 详解Spring技术细节
        • Spring的事务在多线程下是否生效
        • Spring的事务传播机制有哪些
        • Spring在业务中常见的使用方式
        • Spring中如何开启事务
        • Spring中用到了哪些设计模式
      • 详解Spring MVC核心知识点
        • 五、Spring MVC
        • 详解MVC的设计理念
        • SpringMVC是如何将不同的Request路由到不同Controller中的
      • 详解Spring Boot核心知识点
        • 六、Spring Boot 专题
        • Spring Boot 如何让你的 bean 在其他 bean 之前加载
        • 如何用Spring Boot统计一个Bean中的方法调用次数
        • Springboot是如何实现自动配置的
        • SpringBoot是如何实现main方法启动Web项目的
        • 在Spring中如何使用Spring Event做事件驱动
        • SpringBoot中的事务事件如何使用
        • 为什么不建议直接使用SpringBoot的@Async
        • Spring中@Service 、@Component、@Repository等注解区别是什么
        • 如何在SpringBoot启动过程中做缓存预热
        • SpringBoot中如何实现多环境配置
        • 如何开发一个spring boot starter脚手架
        • 介绍下@Scheduled的实现原理以及用法
      • 小结
      • 参考
    • Spring核心功能IOC详解
    • Spring 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-22
目录

Spring 核心知识点全面解析

# 写在文章开头

很多 Java 开发者对 Spring 的认知停留在"会用"层面:

"Bean 怎么创建出来的?不知道" "循环依赖是怎么解决的?看过博客,过两天就忘" "AOP 为什么有时生效、有时不生效?靠试"

知其然更要知其所以然。

本文从源码实现出发,解读 Spring 框架的核心机制:

  • BeanFactory 如何一步步构建 Bean?(三级缓存机制)
  • @Autowired 注入的底层逻辑是什么?(后置处理器链)
  • Spring 事务为何会失效?(代理失效的 6 种场景)
  • @PostConstruct 为何总在 afterPropertiesSet 之前?

读完本文,你不仅能回答"怎么用",更能回答"为什么这样设计"——这才是面试官真正想听到的答案。

你好,我是 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核心知识点

# 一、Spring 基础认知

# 聊聊对Spring的理解

Spring 是一个 轻量级开源框架,核心理念是集大成内置所有开发人员所需要的工具包,避免重复造轮子,专注于业务开发。

其核心功能是 DI(依赖注入) 和 AOP(面向切面编程),使得对 Java Bean 的管理十分便捷。

在此基础上,Spring 生态还提供了丰富的扩展能力:

  • 数据访问:JdbcTemplate 让你只需关注 SQL 逻辑,无需处理连接和异常;@Transactional 一个注解就能开启事务
  • Web 开发:只需一个 @RestController + @GetMapping,几分钟就能搞定一个 REST 接口
  • 集成能力:starter 自动装配,一行依赖即可整合 Redis、MQ、ES 等组件
  • 测试支持:@SpringBootTest 让你无需启动真实容器,即可对整个应用进行集成测试

一句话总结:Spring 通过 IoC/AOP 让 Java 开发更简单、更解耦。

# Spring包含那些模块

Spring 可以分为以下几大类:

分类 核心模块 作用
Core Container spring-core、spring-beans、spring-context、spring-expression IoC 容器、Bean 管理、EL 表达式
AOP spring-aop、spring-aspects 面向切面编程
Web spring-web、spring-webmvc、spring-webflux Web 开发、MVC 模式、响应式编程
Data Access spring-jdbc、spring-tx、spring-orm、spring-jms 数据库访问、事务管理、ORM 框架、消息队列
Test spring-test 单元测试、集成测试支持
Messaging spring-messaging 消息通信

其中,Core Container 是 Spring 的基石,IoC/DI、AOP 等核心功能都依赖于此。

# Spring,Spring MVC,Spring Boot 之间的关系

Spring 提供 IoC 容器 和 AOP 两大核心能力,奠定了 Spring 生态的基础。

Spring MVC 是基于 Spring 的 Web 框架,简化了 Web 开发。相较于传统 Servlet:

维度 Servlet Spring MVC
配置 web.xml 硬编码 注解配置
参数 手动从 request 取 自动绑定到方法参数
视图 手动跳转 视图解析器统一处理
异常 try-catch @ExceptionHandler 统一处理

一句话:把 Servlet 时代那些繁琐的模板代码都封装掉了。

而Spring Boot 在这设计理念之上简化了Spring的种种配置,让我们可以"偷懒":

  1. 开箱即用:引入 starter,一行依赖即可运行
  2. 自动装配:通过 @EnableAutoConfiguration 自动推断并配置所需组件
  3. 内置容器:内置 Tomcat/Jetty,无需单独部署 WAR
  4. 监控管理:actuator 提供应用监控端点

可以说 Spring Boot 通过大量的自动配置技术降低了 Spring 的使用成本。

# 如何根据配置动态生成 Spring 的 Bean

Spring 支持多种方式动态注册 Bean:

  1. @ConfigurationProperties + @EnableConfigurationProperties

    • 将 application.yml 中的配置绑定到 POJO,再注册为 Bean
    • 适合:根据配置生成数据源、Redis 等组件
  2. @Conditional 系列注解

    • 满足条件时才注册 Bean,如 @ConditionalOnClass、@ConditionalOnProperty
    • Spring Boot 自动装配的核心机制
  3. @Profile

    • 通过 spring.profiles.active 激活不同环境的 Bean
    • 如:@Profile("dev")、@Profile("prod")
  4. FactoryBean 接口

    • 实现 FactoryBean<T>,在 getObject() 中自定义 Bean 创建逻辑
    • 如 SqlSessionFactoryBean、RabbitMQConnectionFactoryBean

# Spring 中注入 Bean 有几种方式

方式 示例 说明
XML 配置 <bean><property name="xxx" ref="xxx"/></bean> 传统方式,现在很少用
构造器注入 @Autowired UserService(UserRepository) 推荐,依赖不可变
Setter 注入 @Autowired setXxx(Xxx xxx) 可选注入
字段注入 @Autowired private Xxx xxx 不推荐,无法 final
@Bean 方法 @Bean MyBean() 用于 @Configuration 类
FactoryBean 实现 FactoryBean 接口 自定义创建逻辑

# 二、IoC 与 DI

# 谈谈你对IoC的理解

IoC即控制反转( Inversion Control),I 是反转, C是控制,通俗来说控制反转的意思就是将对象的创建交给外部管理。所以IoC并不是Spring框架特有的,它是一种软件工程设计理念,任何语言都可以基于自己的特质实现这一能力。

但我们就以Spring为例,Spring只要基于几个注解或者xml配置,就能让框架帮我自动管理对象的创建,当我们需要用到这个对象时,只需使用注解或者配置注入即可。这就使得我们后续使用某些类的时候无需关心它内部需要创建那些其他类,无需再一步一步的认为回溯将对象手动创建、管理。

# 介绍一下Spring的AOP

即面向切面编程对应的英文是(aspect-oriented programming),是面向对象思想(oop)的一种补充,基于切面的维度横跨多个对象进行公共逻辑织入,保证业务与非业务功能的解耦。

# 知道什么是Spring bean吗?

与传统 j2EE 企业规范中的 Bean 不同,Spring 中的 Bean 可以是任意 POJO,不受 JavaBean 规范约束。只要交给 Spring 容器管理的对象,就是 Spring Bean。

# 将一个类声明为 Bean 的注解有哪些?

注解 场景
@Component 通用组件,无特定分层
@Controller Spring MVC 控制层
@Service 服务层,业务逻辑
@Repository 持久层,DAO
@Mapper MyBatis Mapper 接口

# @Component 和 @Bean 的区别是什么?

维度 @Component @Bean
作用对象 类 方法
使用场景 我们自己写的类 第三方类,无法加注解
配置方式 扫描即注册 手动在 @Configuration 类中定义

如下所示,我们需要集成第三方组件时,因为无法在类上加注解,所以我们使用@Bean注解:

@Bean(name="redisTemplate")
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, String> template = new RedisTemplate<>();
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        template.setConnectionFactory(factory);
        //key序列化方式
        template.setKeySerializer(redisSerializer);
        //value序列化
        template.setValueSerializer(redisSerializer);
        //value hashmap序列化
        template.setHashValueSerializer(redisSerializer);
        //key haspmap序列化
        template.setHashKeySerializer(redisSerializer);
        //
        return template;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 通过注解注入 Bean 的方式有哪些

常见方式是@Autowired、@Resource、@Inject,这些注解对应来源分别是Spring框架、jdk和JSR-330

注解 来源 注入方式 说明
@Autowired Spring byType → byName 先匹配类型,多个时按字段名
@Resource JDK byName → byType 先匹配名称,默认用字段名
@Inject JSR-330 byType 需要配合 @Named 指定名称

按照现主流开发模式@Autowired最常用,其注入规则是先匹配类型,在按照字段名,如下案例所示,UserService有两个bean实现,为了确保在@Autowired规则下能够正确注入UserServiceImplA,我们的字段名需声明为userServiceImplA:

// 接口
public interface UserService {
    void sayHello();
}

// 实现类
@Service
public class UserServiceImpl implements UserService {
    @Override
    public void sayHello() {
        System.out.println("Hello");
    }
}

// 使用
@Autowired
private UserService userService;  // userService = 字段名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

当存在多个相同类型的 Bean 时,Spring 会按字段名去匹配 Bean 的名称:

@Service
public class UserServiceImplA implements UserService {}

@Service
public class UserServiceImplB implements UserService {}

// ✅ 能匹配
@Autowired
private UserService userServiceImplA;  // 按字段名找到 UserServiceImplA

// ❌ 报错:NoUniqueBeanDefinitionException
@Autowired
private UserService userService;  // 按字段名找不到叫 userService 的 Bean
1
2
3
4
5
6
7
8
9
10
11
12
13

解决多 Bean 冲突:配合 @Qualifier 指定 Bean 名称

@Autowired
@Qualifier("userServiceImplA")
private UserService userService;
1
2
3

# @Autowired 和 @Resource 的区别是什么

维度 @Autowired @Resource
来源 Spring JDK(JSR-250)
注入顺序 byType → byName byName → byType
required 属性 支持 不支持
作用位置 构造器/Setter/字段 字段/Setter

常见问题:当同一接口有多个实现类时

@Service
public class A1 implements A {}

@Service
public class A2 implements A {}

// 使用时报错:NoUniqueBeanDefinitionException
@Autowired
private A a;
1
2
3
4
5
6
7
8
9

解决方案:

  • @Primary:标记优先使用的 Bean
  • @Qualifier("beanName"):指定注入哪个 Bean

# Bean 的作用域有哪些

作用域 说明 使用场景
singleton 默认,每次获取同一实例 所有 Bean
prototype 多例,每次获取新实例 有状态的 Bean
request 每次 HTTP 请求 Web 应用
session 同一 Session Web 应用
application ServletContext 生命周期 Web 应用
websocket WebSocket 会话 WebSocket

针对作用域的配置,对于 xml的话就是<bean id="..." class="..." scope="singleton"></bean>,如果是注解就加给Scope:

@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Person personPrototype() {
    return new Person();
}
1
2
3
4
5

# BeanFactory 和 FactoryBean 的关系

概念 说明
BeanFactory Spring IoC 容器的核心接口,负责 Bean 的创建和管理
FactoryBean 工厂 Bean,用于创建复杂或特殊配置的 Bean

区别:

  • BeanFactory:容器的"管理员",管理所有 Bean
  • FactoryBean:某个 Bean 的"工厂",实现它可以自定义 Bean 创建逻辑

常见实现: SqlSessionFactoryBean、RabbitMQConnectionFactoryBean

# 单例 Bean 的线程安全问题

Spring默认的Bean是单例的,所以在多线程操作当前Bean的情况下,若有实例变量(例如全局容器等)是很可能出现线程安全问题的。常见的解决方案有以下几种:

方案一(推荐):使用无状态 Bean - 不包含可变成员变量,只包含只读操作

@Service
public class UserService {
    // 无状态Bean:所有方法只接收参数,不修改成员变量
    public User findById(Long id) {
        return userRepository.findById(id);
    }

    public List<User> findAll() {
        return userRepository.findAll();
    }
}
1
2
3
4
5
6
7
8
9
10
11

方案二:使用同步锁 - 根据并发场景选用合适的锁

单机场景:使用 synchronized 或 ReentrantLock

@Service
public class CounterService {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }
}
1
2
3
4
5
6
7
8

分布式场景:使用 Redis/ZooKeeper 分布式锁

@Service
public class DistributedCounterService {
    @Autowired
    private StringRedisTemplate redisTemplate;

    public void increment() {
        String lockKey = "counter:lock";
        Boolean locked = redisTemplate.opsForValue()
            .setIfAbsent(lockKey, "1", Duration.ofSeconds(10));
        if (Boolean.TRUE.equals(locked)) {
            try {
                // 业务逻辑
            } finally {
                redisTemplate.delete(lockKey);
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

方案三:使用不可变对象 - 将可变成员变量声明为 final

@Service
public class ConfigService {
    // 不可变对象:所有成员变量都是 final
    private final Map<String, String> config;

    public ConfigService() {
        this.config = Collections.unmodifiableMap(new HashMap<>());
    }

    public String getValue(String key) {
        return config.get(key);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

方案四:使用 ThreadLocal - 管理每个线程的变量副本

@Service
public class TestBean {
    private ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public void doSomething() {
        try {
            threadLocal.set("test");
            // 业务逻辑...
            String value = threadLocal.get();
        } finally {
            // ⚠️ 重要:使用完毕后必须清理,否则可能导致内存泄漏
            threadLocal.remove();
        }
    }

    public String get() {
        return threadLocal.get();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# Spring Bean 的生命周期

完整生命周期包括:实例化 → 属性填充 → 初始化 → 销毁

@Service
public class UserService {

    @Autowired      // ← 属性填充阶段注入
    private UserRepository userRepository;

    @Value("${timeout:30}")  // ← 属性填充阶段注入
    private int timeout;

    @PostConstruct   // ← 初始化阶段执行
    public void init() {
        // 做一些初始化操作,比如校验配置
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

执行顺序:

1. 实例化(new UserService())
         ↓
2. 属性填充(@Autowired、@Value 注入)
         ↓
3. 初始化(@PostConstruct → InitializingBean.afterPropertiesSet → init-method)
         ↓
4. Bean 就绪
1
2
3
4
5
6
7

详细可参考:深入解析 Spring Bean 的生命周期管理 (opens new window)

# Spring默认支持循环依赖吗?如果发生如何解决

什么是循环依赖?

以 AService 和 BService 为例,它们相互依赖:

@Service
public class AService {
    @Autowired
    private BService bService;

    public void doSomething() {
        bService.doOtherThing();
    }
}

@Service
public class BService {
    @Autowired
    private AService aService;

    public void doOtherThing() {
        aService.doSomething();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

上述代码中,AService 需要注入 BService,BService 又需要注入 AService,形成了循环依赖。

默认是不支持,从 Spring Boot 2.6.x 开始默认禁止循环依赖,之前的版本通过三级缓存机制支持单例Bean的字段注入循环依赖。

关键方法是 DefaultSingletonBeanRegistry#getSingleton,它依次查询三级缓存,我们以AService和BService这个互相依赖的场景介绍一下,假设AService 注入 BService时下述代码流程为:

  1. 先看一级(成品bean容器),发现不存在,执行步骤2
  2. 进入二级查看,也不存在,进入步骤3
  3. 重点,如果allowEarlyReference(允许不成熟对象提前暴露)为true,则进入步骤4
  4. 将BService先创建(可能有些依赖对象还没注入),直接暴露
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 1. 先查一级缓存(成品Bean)
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 2. 查二级缓存(早期Bean)
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                // 3. 查三级缓存(工厂),创建早期引用
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    // 放入二级缓存,移除三级缓存
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

对应执行流程如下图,所以要想解决循环依赖问题,最基本的解决方案是将allowEarlyReference = true(配置名spring.main.allow-circular-references) ,让Spring 提前暴露未完成初始化的 Bean 引用给其他 Bean 使用,从而打破循环依赖。但这个"早期引用"存在业务风险,需要谨慎使用:

三级缓存机制流程图

也就是因为上述原因,Spring Boot 2.6+ 默认禁止循环依赖——鼓励开发者通过重构解决设计问题。

解决方案:

方案一(不推荐):通过配置开启循环依赖支持,也就是上文说的将不成熟的对象提前暴露:

# application.properties
spring.main.allow-circular-references=true
1
2

或者在启动类中配置:

public static void main(String[] args) {
    SpringApplication app = new SpringApplication(Application.class);
    app.setAllowCircularReferences(true);
    app.run(args);
}
1
2
3
4
5

方案二:lazy注解懒加载,确保只有被使用时才会显示初始化,如下代码所示,针对需要显示初始化的类,我们首先需要通过Lazy标注声明:

/**
 * 懒加载服务示例
 * 使用@Lazy注解标记,表示该Bean在第一次被请求时才进行初始化
 */
@Service
@Slf4j
@Lazy
public class LazyService {

    public LazyService() {
        log.info("LazyService 初始化完成");
    }

    public String getMessage() {
        return "Hello from LazyService!";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

注入时也是同理,标明懒加载注解,确保只有使用的时候,才会创建bean,由此避免循环依赖:

@Lazy
    @Autowired
    private LazyService lazyService;
1
2
3

方案三:使用Spring容器上下文,这是笔者日常工厂时间中比较常用的一种手段,是破解循环依赖中最有效的手段。本质上,导致循环依赖的原因就是两个bean因为需要对方的能力而互相引用:

循环依赖示意图:A、B互相引用

所以我们是否可以做到,让各个bean完成独立的加载,然后使用时,再引用对象呢?答案是使用Spring容器上下文。我们都知道Spring框架内置了一个ApplicationContext对bean容器进行封装,我们可以通过getBean方法到容器内获取指定的bean对象:

	/**
	 * Spring应用上下文环境
	 */
	private static ApplicationContext applicationContext;
1
2
3
4

所以使用时,我们就可以在需要用到依赖bean的地方显式调用,如下图,以互相依赖的A B两个bean为例,我们编码时不显示注入对方,避免循环依赖检测报错。 当b需要用到a时,通过ApplicationContext(笔者这里用到hutool针对ApplicationContext的封装工具)调用getBean取出依赖对象执行调用:

ApplicationContext获取Bean流程图

对应BService调用代码如下所示,这种做法避免了懒加载带来的延迟开销,本质是通过按需方式完成调用,是Spring工程的最佳实践:

 SpringUtil.getBean(AService.class).doSomething();
1

# 三、Bean 生命周期与循环依赖

# Spring是如何销毁bean的

在bean需要被销毁的时候,我们通过源码可以看到,对bean的销毁用了一个适配器模式DisposableBeanAdapter,感兴趣的读者可以步入看看,实际上这个方法就是判断这个bean有没有实现DisposableBean接口,若没有则看看xml配置有没有配置destroy-method,进而完成适配器的创建,着手销毁bean。

@Override
	public void destroyBean(Object existingBean) {
		new DisposableBeanAdapter(existingBean, getBeanPostProcessors(), getAccessControlContext()).destroy();
	}
1
2
3
4

查看destroy的实现细节可以看到它会先走查看是否有DisposableBean接口实现,如果有则调用,后续则是查看是否xml中有配置指定的销毁发发,若有则直接调用:

public void destroy() {
		

		//如果有继承DisposableBean则调用这个bean类的destroy方法
		if (this.invokeDisposableBean) {
		.....
			try {
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
						((DisposableBean) this.bean).destroy();
						return null;
					}, this.acc);
				}
				else {
					((DisposableBean) this.bean).destroy();
				}
			}
		.......
		}

//反之看看xml中这个bean有没有配置destroy-method,有则调用
		if (this.destroyMethod != null) {
			invokeCustomDestroyMethod(this.destroyMethod);
		}
		else if (this.destroyMethodName != null) {
			Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
			if (methodToInvoke != null) {
				invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
			}
		}
	}
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

# 为什么Spring不建议使用基于字段的依赖注入

主要有以下几点原因:

1. 违反单一职责原则(SOLID)

字段注入让依赖关系隐藏在类内部,类的职责变得不清晰。

2. 构造方法中无法使用注入的依赖

Bean 初始化顺序:实例化 → 构造方法 → 依赖注入,所以在构造方法中使用 @Autowired 注入的字段会是 null:

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public UserService() {
        // ❌ userRepository 还是 null,此时无法使用
        // userRepository.findAll(); // 会报 NullPointerException
    }
}
1
2
3
4
5
6
7
8
9
10

解决方案:使用构造方法注入

@Service
public class UserService {
    private final UserRepository userRepository;

    // ✅ 构造方法注入,依赖在构造时已就绪
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
        this.userRepository.findAll(); // 正常工作
    }
}
1
2
3
4
5
6
7
8
9
10

3. 隐藏依赖关系,违背封装性

通过私有字段注入,类的依赖关系不明确,代码可读性差。

4. 单元测试困难

依赖隐藏在字段中,Mock 时需要反射或启动整个容器:

// 字段注入:测试时必须启动 Spring 容器
@Autowired
private UserService userService;

// 构造方法注入:可以直接 new
private UserRepository mockRepository;
private UserService userService = new UserService(mockRepository);
1
2
3
4
5
6
7

# @PostConstruct、init-method和afterPropertiesSet执行顺序

从源码中可知:

  1. @PostConstruct 在 Bean 属性填充完成后、初始化阶段中调用,对应的处理器是 CommonAnnotationBeanPostProcessor,我们从该源码中看到它通过 setInitAnnotationType 方法注册了 PostConstruct 注解。
public CommonAnnotationBeanPostProcessor() {
		setOrder(Ordered.LOWEST_PRECEDENCE - 3);
		setInitAnnotationType(PostConstruct.class);
		setDestroyAnnotationType(PreDestroy.class);
		ignoreResourceType("javax.xml.ws.WebServiceContext");
	}
1
2
3
4
5
6
  1. 然后就是调用InitializingBean的afterPropertiesSet 。
  2. 最后是调用我们文件配置的 init-method。

对应的我们可以在AbstractAutowireCapableBeanFactory的invokeInitMethods印证这一点:

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {

		boolean isInitializingBean = (bean instanceof InitializingBean);
		if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
			
			if (System.getSecurityManager() != null) {
			//......
			}
			else {
			//调用InitializingBean接口的afterPropertiesSet
				((InitializingBean) bean).afterPropertiesSet();
			}
		}

		//调用自定义init-method
		if (mbd != null && bean.getClass() != NullBean.class) {
			String initMethodName = mbd.getInitMethodName();
			if (StringUtils.hasLength(initMethodName) &&
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}
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

# Spring中shutdownhook作用是什么

Spring框架所提供的关闭钩子,启动时Spring会向JVM注册一个shutdownhook,当程序关闭的时候就会触发我们所实现的DisposableBean或者配置的销毁方法完成最后清理操作。

对应我们可以在AbstractAutowireCapableBeanFactory的doCreateBean看到该方法的实现,其内部就会检查当前bean是否是DisposableBean类型,如果是则将该方法注册,在容器销毁时会调用destroy方法:

// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
1
2
3
4

# 四、AOP 与事务

# Spring的AOP在什么场景下会失效

大体来说基本都是代理创建失败或者未能正确的调用到代理所导致:

  1. 方法私有化 - private 方法无法被代理类覆盖,AOP 无法织入
  2. 静态方法 - static 方法属于类本身,不经过 Spring 代理,AOP 无法织入
  3. final 修饰方法 - final 方法无法被子类重写,AOP 无法织入
  4. 同类内部调用(this 调用) - 通过 this.method() 调用同类方法时,绕过了代理对象,直接调用目标对象的方法,导致 AOP 增强失效
  5. 异常被 catch 吞掉 - 业务方法捕获异常后未重新抛出,代理无法感知异常,事务无法回滚(如 @Transactional 失效)

# 详解Spring技术细节

# Spring的事务在多线程下是否生效

如果异步且通过注解Transactional注解标记的,因为事务是通过threadLocal来维护当前线程的内部map记录connection信息,这意味着异步提交到别的线程后connection信息就取不到即无法回滚错误事务了。 对此我们给出DataSourceTransactionManager的事务开启方法doBegin:

@Override
	protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;

		try {
			//......
			//拿到当前线程持有的连接
			txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
			con = txObject.getConnectionHolder().getConnection();

			//......
			//设置自动提交为false
			if (con.getAutoCommit()) {
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				con.setAutoCommit(false);
			}

			//......

			//通过threadLocal绑定到当前线程的map中
			if (txObject.isNewConnectionHolder()) {
				TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
			}
		}

		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

针对该问题,我们要从三种情况考虑:

情况一: @Transactional 和@Async在同一个代理类的方法上

@Async
@Transactional(rollbackFor = Exception.class)
public Integer saveOrderInfo(Order order, TUser user) {
    userMapper.insert(user);
    return orderMapper.insert(order);
}
1
2
3
4
5
6

这种情况被外部调用时,本质上就是通过异步线程池调用代理类增强后的方法,所以代理类还是生效的:

情况二: @Transactional 调用 @Async

@Transactional(rollbackFor = Exception.class)
public void save(Order order, TUser user) {
    SpringUtil.getBean(OrderService.class).saveOrderInfo(order, user);
}

@Async
public Integer saveOrderInfo(Order order, TUser user) {
    userMapper.insert(user);
    return orderMapper.insert(order);
}
1
2
3
4
5
6
7
8
9
10

这会使得saveOrderInfo方法被提交到异步线程池,对应的connection信息对save方法无感知无法进行回滚,事务不生效:

情况三: @Async 调用 @Transactional

@Async
public void save(Order order, TUser user) {
		//.....其他SQL操作
    SpringUtil.getBean(OrderService.class).saveOrderInfo(order, user);
}

@Transactional(rollbackFor = Exception.class)
public Integer saveOrderInfo(Order order, TUser user) {
    userMapper.insert(user);
    return orderMapper.insert(order);
}
1
2
3
4
5
6
7
8
9
10
11

这种情况下,事务仅仅针对在saveOrderInfo方法中,所以 save 方法中的操作不受事务保护,但如果 saveOrderInfo 方法内抛异常,该方法内的操作会回滚:

# Spring的事务传播机制有哪些

Spring 提供了 7 种传播行为:

传播行为 说明
REQUIRED(默认) 如果当前有事务,加入该事务;否则新建事务
REQUIRES_NEW 总是新建事务,挂起当前事务
SUPPORTS 如果当前有事务,加入事务;否则非事务执行
NOT_SUPPORTED 非事务执行,挂起当前事务
MANDATORY 必须在事务中执行,否则抛异常
NEVER 必须非事务执行,否则抛异常
NESTED 如果当前有事务,在嵌套事务中执行

详细可参考:探索 Spring 事务的奥秘 (opens new window)

# Spring在业务中常见的使用方式

  1. 基于IOC完成策略模式
  2. 基于AOP进行日志采集、逻辑校验、异常捕获。
  3. 事务管理数据持久化保证多表操作ACID。
  4. 通过Event异步解耦功能。

# Spring中如何开启事务

  1. 编程式事务:用TransactionTemplate的execute方法提交逻辑完成编程式事务。
  2. 声明式事务:用Transactional注解。

# Spring中用到了哪些设计模式

详情可以参考笔者这篇文章,论 Spring 框架所运用的设计模式:https://mp.weixin.qq.com/s/L82TPwjtAiRoyEsCqC0BVw (opens new window)

# 详解Spring MVC核心知识点

# 五、Spring MVC

# 详解MVC的设计理念

MVC 是 Web 开发经典的分层模式:

层级 职责
Model 数据和业务逻辑
View 用户界面展示
Controller 接收请求,调用 Model 处理,响应 View

# SpringMVC是如何将不同的Request路由到不同Controller中的

深入解读 Spring MVC:Web 开发的得力助手 :https://mp.weixin.qq.com/s/gzW1Mhw06Zz6yjzsjucC9Q (opens new window)

# 详解Spring Boot核心知识点

# 六、Spring Boot 专题

# Spring Boot 如何让你的 bean 在其他 bean 之前加载

这一点我们查看依赖注入的源码即可知晓,一般来说主动注入的时候这些bean都会优先加载,所以要想实现这一点无非用以下几种手段:

  1. 直接使用Autowired注解,如下所示,一旦容器扫描到TDataService发现其依赖TDataMapper 时,若发现容器还未初始化TDataMapper ,则会优先将这个Bean加载:
@Service
public class TDataService {
    @Autowired
    private TDataMapper tDataMapper;
1
2
3
4
  1. 我们同样可以通过DependsOn注解,明确告知配置类在加载TDataService前先加载tDataMapper:
	@Bean
    @DependsOn("tDataMapper")
    public TDataService tDataService() {
        return new TDataService();
    }
1
2
3
4
5
  1. 基于Spring拓展点,即在实现BeanFactoryPostProcessor的postProcessBeanFactory,通过BeanFactory完全加载BeanDefinition之后,通过该方法找到容器找到bean的定义通过反射完成创建beanInstance并返回:
 @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanA bean = beanFactory.getBean(BeanA.class);
    }
1
2
3
4

# 如何用Spring Boot统计一个Bean中的方法调用次数

针对某个请求方法通过AOP切面配合原子类计数:

@Aspect
@Component
@Slf4j
public class CalculateAspect {

    private AtomicInteger requestCount = new AtomicInteger(0);

    // 定义切点:拦截所有 controller 包下的 public 方法
    @Pointcut("execution(public * com.*.*(..))")
    public void controllerPointcut() {}

    // 获取调用次数
    public int getRequestCount() {
        return requestCount.get();
    }

    // 环绕通知:方法执行前后都计数
    @Around("controllerPointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 方法执行前计数
        requestCount.incrementAndGet();
        // 执行目标方法
        return joinPoint.proceed();
    }
}
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

# Springboot是如何实现自动配置的

Spring Boot自动装配原理以及实践:https://mp.weixin.qq.com/s/GYlMV53Uak1gQ-OkA9lR8g (opens new window)

# SpringBoot是如何实现main方法启动Web项目的

  1. 调用run方法启动时,Spring会自动扫描所有Spring组件完成web相关的依赖加载。
  2. 基于默认配置将内嵌的tomcat服务器启动。
  3. 完成启动处理所有web请求。

# 在Spring中如何使用Spring Event做事件驱动

  1. 继承Event类实现事件,
  2. 基于EventListener注解编写监听方法监听指定的事件
  3. 发布自定义实现的事件。
// 1. 定义事件:继承 ApplicationEvent
public class OrderCreatedEvent extends ApplicationEvent {
    private final Order order;
    public OrderCreatedEvent(Object source, Order order) {
        super(source);
        this.order = order;
    }
}

// 2. 定义监听器:@EventListener 监听指定事件
@Component
public class OrderEventListener {

    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println("收到订单创建事件:" + event.getOrder().getId());
        // 发短信、发邮件等后续操作
    }
}

// 3. 发布事件:ApplicationEventPublisher
@Service
public class OrderService {
    @Autowired
    private ApplicationEventPublisher publisher;

    public void createOrder(Order order) {
        // 创建订单逻辑...
        // 发布事件
        publisher.publishEvent(new OrderCreatedEvent(this, order));
    }
}
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
收到订单创建事件:ORDER-20240101-001
1

# SpringBoot中的事务事件如何使用

以笔者为例最常用到i的就是事务监听注解TransactionalEventListener,当事务触发回滚时就可以通过事件监听感知回滚,基于这个拓展点,我们就可以感知事务回滚进行针对性的处理。

参考:事务监听详解 (opens new window)

# 为什么不建议直接使用SpringBoot的@Async

默认情况下通过@Async提交异步任务会通过SimpleAsyncTaskExecutor处理,查看doExecute方法可以看到,其本质上就是创建一个全新的线程处理任务,若频繁调用则会导致创建大量线程,导致操作系统上下文切换开销增大:

protected void doExecute(Runnable task) {
		Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
		thread.start();
	}
1
2
3
4

# Spring中@Service 、@Component、@Repository等注解区别是什么

本质上都是对于bean的描述,只是语义上的区别:

  1. @Service :标记为服务层组件。
  2. @Component:表示该类为Spring的组件
  3. @Repository:标记为持久层组件,会触发异常转换功能:
    • JPA 场景:Spring 会自动注册 PersistenceExceptionTranslationPostProcessor,将底层数据库异常(如 SQLException)转换为 Spring 的统一 DataAccessException 体系,让业务层无需关心具体数据库的异常类型
    • MyBatis 场景:MyBatis 自带异常转换,无需依赖 @Repository 的异常转换功能,此时 @Repository 更多起语义化作用

这里笔者特别针对Repository源码进行特殊说明,被Repository标注的持久层组件,会被PersistenceExceptionTranslationPostProcessor处理,通过PersistenceExceptionTranslationAdvisor增强即设置PersistenceExceptionTranslationInterceptor拦截器,一旦感知异常则抛出DataAccessException:

@Repository异常转换拦截器流程图

与上图对应,我们给出织入@Repository的拦截器PersistenceExceptionTranslationInterceptor核心代码段,可以看到其内部通过try块执行调用,针对运行时异常统一通过DataAccessUtils抛出DataAccessException

@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
    try {
        return mi.proceed();
    }
    catch (RuntimeException ex) {
        //......
        //统一针对异常抛出DataAccessException
        throw DataAccessUtils.translateIfNecessary(ex, translator);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 如何在SpringBoot启动过程中做缓存预热

CommandLineRunner 的 run 方法会在容器初始化完成后执行,适合做缓存预热。

从 SpringApplication 的 run 方法可以看到,完成所有前置工作后会调用 callRunners,这就是 CommandLineRunner 的执行时机:

public ConfigurableApplicationContext run(String... args) {
    // ... 前置准备工作
    callRunners(context, applicationArguments);
    return context;
}
1
2
3
4
5

代码示例:

@Component
public class CacheWarmUpRunner implements CommandLineRunner {

    @Autowired
    private DictMapper dictMapper;

    @Autowired
    private JedisPool jedisPool;

    private static final String DICT_CACHE_KEY = "sys:dict:";

    @Override
    public void run(String... args) {
        try (Jedis jedis = jedisPool.getResource()) {
            // 查询数据库字典数据
            List<Dict> dictList = dictMapper.selectAll();
            // 写入 Redis 缓存
            for (Dict dict : dictList) {
                String key = DICT_CACHE_KEY + dict.getType() + ":" + dict.getCode();
                jedis.set(key, dict.getValue());
            }
            System.out.println("缓存预热完成,共加载 " + dictList.size() + " 条字典数据");
        }
    }
}
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

# SpringBoot中如何实现多环境配置

编写多个配置文件,再通过application的配置-Dspring.profiles.active决定,例如:

-Dspring.profiles.active=prod
1

# 如何开发一个spring boot starter脚手架

深入解读 Spring MVC:Web 开发的得力助手 :https://mp.weixin.qq.com/s/gzW1Mhw06Zz6yjzsjucC9Q (opens new window)

# 介绍下@Scheduled的实现原理以及用法

该注解注明的任务会被扩展点ScheduledAnnotationBeanPostProcessor处理,如下postProcessAfterInitialization所示,本质上就是扫描到该注解注明的所有方法生成annotatedMethods ,然后调用processScheduled(其内部就是调用scheduleFixedDelayTask)生成延迟任务并提交:

@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		//......

		Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
		if (!this.nonAnnotatedClasses.contains(targetClass) &&
				AnnotationUtils.isCandidateClass(targetClass, Arrays.asList(Scheduled.class, Schedules.class))) {
				//获取所有添加注解的方法
			Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
					(MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {
						Set<Scheduled> scheduledAnnotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(
								method, Scheduled.class, Schedules.class);
						return (!scheduledAnnotations.isEmpty() ? scheduledAnnotations : null);
					});
					
			if (annotatedMethods.isEmpty()) {
			//......
			}
			else {
				//遍历这些方法生成任务提交到延迟队列中
				annotatedMethods.forEach((method, scheduledAnnotations) ->
						scheduledAnnotations.forEach(scheduled -> processScheduled(scheduled, method, bean)));
				//......
			}
		}
		return bean;
	}
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

# 小结

通过对 Spring 核心知识点的全面解析,我们对其有了更深入的理解。

Spring 的控制反转(IoC)实现了对象之间依赖关系的灵活管理,极大地降低了代码的耦合度。依赖注入方式让组件的装配更加便捷高效。Spring 的面向切面编程(AOP)为横切关注点的处理提供了强大支持,能够在不影响业务代码的情况下实现诸如日志记录、事务管理、安全控制等功能。其 Bean 的生命周期管理确保了 Bean 在不同阶段的正确处理和行为。配置管理方面,无论是 XML 配置还是基于注解的配置,都为项目的搭建和定制提供了丰富的手段。Spring 还提供了对数据访问、事务管理等方面的良好集成和支持,使开发更加顺畅。

你好,我是 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 常见面试题总结:https://javaguide.cn/system-design/framework/spring/spring-knowledge-and-questions-summary.html#bean-的生命周期了解么 (opens new window)

Spring Bean的生命周期(非常详细):https://www.cnblogs.com/zrtqsk/p/3735273.html (opens new window)

Spring Bean的作用域:https://blog.csdn.net/kongmin_123/article/details/82048392 (opens new window)

编辑 (opens new window)
上次更新: 2026/03/23, 09:45:22
探索JVM的隐秘角落:元空间详解
Spring核心功能IOC详解

← 探索JVM的隐秘角落:元空间详解 Spring核心功能IOC详解→

最近更新
01
千万级交易流水慢查询综合治理实践
05-14
02
记一次StarRocks源码级排错和既有架构优化实践
05-13
03
对账核销场景设计与重构实践
05-12
更多文章>
Theme by Vdoing | Copyright © 2025-2026 Evan Xu | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×
×