Java学习指南
  • Java 编程的逻辑
  • Java进阶
  • Java FrameWorks
  • 了解 USB Type-A,B,C 三大标准接口
  • 深入浅出DDD
  • 重构:改善既有代码的设计
  • 面试大纲
  • 云原生
    • 什么是无服务器(what is serverless)?
  • 博客
    • 深入分析Log4j 漏洞
  • 博客
    • Serverless之快速搭建Spring Boot应用
  • 博客
    • 使用 Prometheus + Grafana + Spring Boot Actuator 监控应用
  • 博客
    • 使用 Prometheus + Grafana 监控 MySQL
  • 博客
    • 使用Github Actions + Docker 部署Spring Boot应用
  • 博客
    • Redis分布式锁之Redisson的原理和实践
  • 博客
    • 数据库中的树结构应该怎样去设计
  • 学习&成长
    • 如何成为技术大牛
  • 开发工具
    • Git Commit Message Guidelines
  • 开发工具
    • git命名大全
  • 开发工具
    • Gradle vs Maven Comparison
  • 开发工具
    • Swagger2常用注解及其说明
  • 开发工具
    • 简明 VIM 练级攻略
  • 微服务
    • 十大微服务设计模式和原则
  • 微服务
    • 微服务下的身份认证和令牌管理
  • 微服务
    • 微服务坏味道之循环依赖
  • 设计模式
    • 设计模式 - JDK中的设计模式
  • 设计模式
    • 设计模式 - Java三种代理模式
  • 设计模式
    • 设计模式 - 六大设计原则
  • 设计模式
    • 设计模式 - 单例模式
  • 设计模式
    • 设计模式 - 命名模式
  • 设计模式
    • 设计模式 - 备忘录模式
  • 设计模式
    • 设计模式 - 概览
  • 设计模式
    • 设计模式 - 没用的设计模式
  • 质量&效率
    • Homebrew 替换国内镜像源
  • 质量&效率
    • 工作中如何做好技术积累
  • Java FrameWorks
    • Logback
      • 自定义 logback 日志过滤器
  • Java FrameWorks
    • Mybatis
      • MyBatis(十三) - 整合Spring
  • Java FrameWorks
    • Mybatis
      • MyBatis(十二) - 一些API
  • Java FrameWorks
    • Mybatis
      • Mybatis(一) - 概述
  • Java FrameWorks
    • Mybatis
      • Mybatis(七) - 结果集的封装与映射
  • Java FrameWorks
    • Mybatis
      • Mybatis(三) - mapper.xml及其加载机制
  • Java FrameWorks
    • Mybatis
      • Mybatis(九) - 事务
  • Java FrameWorks
    • Mybatis
      • Mybatis(二) - 全局配置文件及其加载机制
  • Java FrameWorks
    • Mybatis
      • Mybatis(五) - SqlSession执行流程
  • Java FrameWorks
    • Mybatis
      • Mybatis(八) - 缓存
  • Java FrameWorks
    • Mybatis
      • Mybatis(六) - 动态SQL的参数绑定与执行
  • Java FrameWorks
    • Mybatis
      • Mybatis(十) - 插件
  • Java FrameWorks
    • Mybatis
      • Mybatis(十一) - 日志
  • Java FrameWorks
    • Mybatis
      • Mybatis(四) - Mapper接口解析
  • Java FrameWorks
    • Netty
      • Netty 可靠性分析
  • Java FrameWorks
    • Netty
      • Netty - Netty 线程模型
  • Java FrameWorks
    • Netty
      • Netty堆外内存泄露排查盛宴
  • Java FrameWorks
    • Netty
      • Netty高级 - 高性能之道
  • Java FrameWorks
    • Shiro
      • Shiro + JWT + Spring Boot Restful 简易教程
  • Java FrameWorks
    • Shiro
      • 非常详尽的 Shiro 架构解析!
  • Java FrameWorks
    • Spring
      • Spring AOP 使用介绍,从前世到今生
  • Java FrameWorks
    • Spring
      • Spring AOP 源码解析
  • Java FrameWorks
    • Spring
      • Spring Event 实现原理
  • Java FrameWorks
    • Spring
      • Spring Events
  • Java FrameWorks
    • Spring
      • Spring IOC容器源码分析
  • Java FrameWorks
    • Spring
      • Spring Integration简介
  • Java FrameWorks
    • Spring
      • Spring MVC 框架中拦截器 Interceptor 的使用方法
  • Java FrameWorks
    • Spring
      • Spring bean 解析、注册、实例化流程源码剖析
  • Java FrameWorks
    • Spring
      • Spring validation中@NotNull、@NotEmpty、@NotBlank的区别
  • Java FrameWorks
    • Spring
      • Spring 如何解决循环依赖?
  • Java FrameWorks
    • Spring
      • Spring 异步实现原理与实战分享
  • Java FrameWorks
    • Spring
      • Spring中的“for update”问题
  • Java FrameWorks
    • Spring
      • Spring中的设计模式
  • Java FrameWorks
    • Spring
      • Spring事务失效的 8 大原因
  • Java FrameWorks
    • Spring
      • Spring事务管理详解
  • Java FrameWorks
    • Spring
      • Spring计时器StopWatch使用
  • Java FrameWorks
    • Spring
      • 详述 Spring MVC 框架中拦截器 Interceptor 的使用方法
  • Java FrameWorks
    • Spring
      • 透彻的掌握 Spring 中@transactional 的使用
  • Java
    • Java IO&NIO&AIO
      • Java IO - BIO 详解
  • Java
    • Java IO&NIO&AIO
      • Java NIO - IO多路复用详解
  • Java
    • Java IO&NIO&AIO
      • Java N(A)IO - Netty
  • Java
    • Java IO&NIO&AIO
      • Java IO - Unix IO模型
  • Java
    • Java IO&NIO&AIO
      • Java IO - 分类
  • Java
    • Java IO&NIO&AIO
      • Java NIO - 基础详解
  • Java
    • Java IO&NIO&AIO
      • Java IO - 常见类使用
  • Java
    • Java IO&NIO&AIO
      • Java AIO - 异步IO详解
  • Java
    • Java IO&NIO&AIO
      • Java IO概述
  • Java
    • Java IO&NIO&AIO
      • Java IO - 设计模式
  • Java
    • Java IO&NIO&AIO
      • Java NIO - 零拷贝实现
  • Java
    • Java JVM
      • JVM 优化经验总结
  • Java
    • Java JVM
      • JVM 内存结构
  • Java
    • Java JVM
      • JVM参数设置
  • Java
    • Java JVM
      • Java 内存模型
  • Java
    • Java JVM
      • 从实际案例聊聊Java应用的GC优化
  • Java
    • Java JVM
      • Java 垃圾回收器G1详解
  • Java
    • Java JVM
      • 垃圾回收器Shenandoah GC详解
  • Java
    • Java JVM
      • 垃圾回收器ZGC详解
  • Java
    • Java JVM
      • 垃圾回收基础
  • Java
    • Java JVM
      • 如何优化Java GC
  • Java
    • Java JVM
      • 类加载机制
  • Java
    • Java JVM
      • 类字节码详解
  • Java
    • Java 基础
      • Java hashCode() 和 equals()
  • Java
    • Java 基础
      • Java 基础 - Java native方法以及JNI实践
  • Java
    • Java 基础
      • Java serialVersionUID 有什么作用?
  • Java
    • Java 基础
      • Java 泛型的类型擦除
  • Java
    • Java 基础
      • Java 基础 - Unsafe类解析
  • Java
    • Java 基础
      • Difference Between Statement and PreparedStatement
  • Java
    • Java 基础
      • Java 基础 - SPI机制详解
  • Java
    • Java 基础
      • Java 基础 - final
  • Java
    • Java 基础
      • Java中static关键字详解
  • Java
    • Java 基础
      • 为什么说Java中只有值传递?
  • Java
    • Java 基础
      • Java 基础 - 即时编译器原理解析及实践
  • Java
    • Java 基础
      • Java 基础 - 反射
  • Java
    • Java 基础
      • Java多态的面试题
  • Java
    • Java 基础
      • Java 基础 - 异常机制详解
  • Java
    • Java 基础
      • 为什么要有抽象类?
  • Java
    • Java 基础
      • 接口的本质
  • Java
    • Java 基础
      • Java 基础 - 枚举
  • Java
    • Java 基础
      • Java 基础 - 泛型机制详解
  • Java
    • Java 基础
      • Java 基础 - 注解机制详解
  • Java
    • Java 基础
      • 为什么 String hashCode 方法选择数字31作为乘子
  • Java
    • Java 并发
      • Java 并发 - 14个Java并发容器
  • Java
    • Java 并发
      • Java 并发 - AQS
  • Java
    • Java 并发
      • Java 并发 - BlockingQueue
  • Java
    • Java 并发
      • Java 并发 - CAS
  • Java
    • Java 并发
      • Java 并发 - Condition接口
  • Java
    • Java 并发
      • Java 并发 - CopyOnWriteArrayList
  • Java
    • Java 并发
      • Java 并发 - CountDownLatch、CyclicBarrier和Phaser对比
  • Java
    • Java 并发
      • Java 并发 - Fork&Join框架
  • Java
    • Java 并发
      • Java 并发 - Java CompletableFuture 详解
  • Java
    • Java 并发
      • Java 并发 - Java 线程池
  • Java
    • Java 并发
      • Java 并发 - Lock接口
  • Java
    • Java 并发
      • Java 并发 - ReentrantLock
  • Java
    • Java 并发
      • Java 并发 - ReentrantReadWriteLock
  • Java
    • Java 并发
      • Java 并发 - Synchronized
  • Java
    • Java 并发
      • Java 并发 - ThreadLocal 内存泄漏问题
  • Java
    • Java 并发
      • Java 并发 - ThreadLocal
  • Java
    • Java 并发
      • Java 并发 - Volatile
  • Java
    • Java 并发
      • Java 并发 - 从ReentrantLock的实现看AQS的原理及应用
  • Java
    • Java 并发
      • Java 并发 - 公平锁和非公平锁
  • Java
    • Java 并发
      • Java 并发 - 内存模型
  • Java
    • Java 并发
      • Java 并发 - 原子类
  • Java
    • Java 并发
      • Java 并发 - 如何确保三个线程顺序执行?
  • Java
    • Java 并发
      • Java 并发 - 锁
  • Java
    • Java 的新特性
      • Java 10 新特性概述
  • Java
    • Java 的新特性
      • Java 11 新特性概述
  • Java
    • Java 的新特性
      • Java 12 新特性概述
  • Java
    • Java 的新特性
      • Java 13 新特性概述
  • Java
    • Java 的新特性
      • Java 14 新特性概述
  • Java
    • Java 的新特性
      • Java 15 新特性概述
  • Java
    • Java 的新特性
      • Java 8的新特性
  • Java
    • Java 的新特性
      • Java 9 新特性概述
  • Java
    • Java 调试排错
      • 调试排错 - Java Debug Interface(JDI)详解
  • Java
    • Java 调试排错
      • 调试排错 - CPU 100% 排查优化实践
  • Java
    • Java 调试排错
      • 调试排错 - Java Heap Dump分析
  • Java
    • Java 调试排错
      • 调试排错 - Java Thread Dump分析
  • Java
    • Java 调试排错
      • 调试排错 - Java动态调试技术原理
  • Java
    • Java 调试排错
      • 调试排错 - Java应用在线调试Arthas
  • Java
    • Java 调试排错
      • 调试排错 - Java问题排查:工具单
  • Java
    • Java 调试排错
      • 调试排错 - 内存溢出与内存泄漏
  • Java
    • Java 调试排错
      • 调试排错 - 在线分析GC日志的网站GCeasy
  • Java
    • Java 调试排错
      • 调试排错 - 常见的GC问题分析与解决
  • Java
    • Java 集合
      • Java 集合 - ArrayList
  • Java
    • Java 集合
      • Java 集合 - HashMap 和 ConcurrentHashMap
  • Java
    • Java 集合
      • Java 集合 - HashMap的死循环问题
  • Java
    • Java 集合
      • Java 集合 - LinkedHashSet&Map
  • Java
    • Java 集合
      • Java 集合 - LinkedList
  • Java
    • Java 集合
      • Java 集合 - PriorityQueue
  • Java
    • Java 集合
      • Java 集合 - Stack & Queue
  • Java
    • Java 集合
      • Java 集合 - TreeSet & TreeMap
  • Java
    • Java 集合
      • Java 集合 - WeakHashMap
  • Java
    • Java 集合
      • Java 集合 - 为什么HashMap的容量是2的幂次方
  • Java
    • Java 集合
      • Java 集合 - 概览
  • Java
    • Java 集合
      • Java 集合 - 高性能队列Disruptor详解
  • 分布式
    • RPC
      • ⭐️RPC - Dubbo&hsf&Spring cloud的区别
  • 分布式
    • RPC
      • ⭐️RPC - Dubbo的架构原理
  • 分布式
    • RPC
      • ⭐️RPC - HSF的原理分析
  • 分布式
    • RPC
      • ⭐️RPC - 你应该知道的RPC原理
  • 分布式
    • RPC
      • ⭐️RPC - 动态代理
  • 分布式
    • RPC
      • 深入理解 RPC 之协议篇
  • 分布式
    • RPC
      • RPC - 序列化和反序列化
  • 分布式
    • RPC
      • ⭐️RPC - 服务注册与发现
  • 分布式
    • RPC
      • RPC - 核心原理
  • 分布式
    • RPC
      • ⭐️RPC - 框架对比
  • 分布式
    • RPC
      • ⭐️RPC - 网络通信
  • 分布式
    • 分布式事务
      • 分布式事务 Seata TCC 模式深度解析
  • 分布式
    • 分布式事务
      • 分布式事务的实现原理
  • 分布式
    • 分布式事务
      • 常用的分布式事务解决方案
  • 分布式
    • 分布式事务
      • 手写实现基于消息队列的分布式事务框架
  • 分布式
    • 分布式算法
      • CAP 定理的含义
  • 分布式
    • 分布式算法
      • Paxos和Raft比较
  • 分布式
    • 分布式算法
      • 分布式一致性与共识算法
  • 分布式
    • 分布式锁
      • ⭐️分布式锁的原理及实现方式
  • 分布式
    • 搜索引擎
      • ElasticSearch与SpringBoot的集成与JPA方法的使用
  • 分布式
    • 搜索引擎
      • 全文搜索引擎 Elasticsearch 入门教程
  • 分布式
    • 搜索引擎
      • 十分钟学会使用 Elasticsearch 优雅搭建自己的搜索系统
  • 分布式
    • 搜索引擎
      • 腾讯万亿级 Elasticsearch 技术解密
  • 分布式
    • 日志系统
      • Grafana Loki 简明教程
  • 分布式
    • 日志系统
      • 分布式系统中如何优雅地追踪日志
  • 分布式
    • 日志系统
      • 如何优雅地记录操作日志?
  • 分布式
    • 日志系统
      • 日志收集组件—Flume、Logstash、Filebeat对比
  • 分布式
    • 日志系统
      • 集中式日志系统 ELK 协议栈详解
  • 分布式
    • 消息队列
      • 消息队列 - Kafka
  • 分布式
    • 消息队列
      • 消息队列 - Kafka、RabbitMQ、RocketMQ等消息中间件的对比
  • 分布式
    • 消息队列
      • 消息队列之 RabbitMQ
  • 分布式
    • 消息队列
      • 消息队列 - 使用docker-compose构建kafka集群
  • 分布式
    • 消息队列
      • 消息队列 - 分布式系统与消息的投递
  • 分布式
    • 消息队列
      • 消息队列 - 如何保证消息的可靠性传输
  • 分布式
    • 消息队列
      • 消息队列 - 如何保证消息的顺序性
  • 分布式
    • 消息队列
      • 消息队列 - 如何保证消息队列的高可用
  • 分布式
    • 消息队列
      • 消息队列 - 消息队列设计精要
  • 分布式
    • 监控系统
      • 深度剖析开源分布式监控CAT
  • 大数据
    • Flink
      • Flink架构与核心组件
  • 微服务
    • Dubbo
      • 基于dubbo的分布式应用中的统一异常处理
  • 微服务
    • Dubbo
      • Vim快捷键
  • 微服务
    • Service Mesh
      • Istio 是什么?
  • 微服务
    • Service Mesh
      • OCTO 2.0:美团基于Service Mesh的服务治理系统详解
  • 微服务
    • Service Mesh
      • Service Mesh是什么?
  • 微服务
    • Service Mesh
      • Spring Cloud向Service Mesh迁移
  • 微服务
    • Service Mesh
      • 数据挖掘算法
  • 微服务
    • Service Mesh
      • Seata Saga 模式
  • 微服务
    • Spring Cloud
      • Seata TCC 模式
  • 微服务
    • Spring Cloud
      • Spring Cloud Config
  • 微服务
    • Spring Cloud
      • Seata AT 模式
  • 微服务
    • Spring Cloud
      • Spring Cloud Gateway
  • 微服务
    • Spring Cloud
      • Spring Cloud OpenFeign 的核心原理
  • 微服务
    • Spring Cloud
      • Seata XA 模式
  • 数据库
    • Database Version Control
      • Liquibase vs. Flyway
  • 数据库
    • Database Version Control
      • Six reasons to version control your database
  • 数据库
    • MySQL
      • How Sharding Works
  • 数据库
    • MySQL
      • MySQL InnoDB中各种SQL语句加锁分析
  • 数据库
    • MySQL
      • MySQL 事务隔离级别和锁
  • 数据库
    • MySQL
      • MySQL 索引性能分析概要
  • 数据库
    • MySQL
      • MySQL 索引设计概要
  • 数据库
    • MySQL
      • MySQL出现Waiting for table metadata lock的原因以及解决方法
  • 数据库
    • MySQL
      • MySQL的Limit性能问题
  • 数据库
    • MySQL
      • MySQL索引优化explain
  • 数据库
    • MySQL
      • MySQL索引背后的数据结构及算法原理
  • 数据库
    • MySQL
      • MySQL行转列、列转行问题
  • 数据库
    • MySQL
      • 一条SQL更新语句是如何执行的?
  • 数据库
    • MySQL
      • 一条SQL查询语句是如何执行的?
  • 数据库
    • MySQL
      • 为什么 MySQL 使用 B+ 树
  • 数据库
    • MySQL
      • 为什么 MySQL 的自增主键不单调也不连续
  • 数据库
    • MySQL
      • 为什么我的MySQL会“抖”一下?
  • 数据库
    • MySQL
      • 为什么数据库不应该使用外键
  • 数据库
    • MySQL
      • 为什么数据库会丢失数据
  • 数据库
    • MySQL
      • 事务的可重复读的能力是怎么实现的?
  • 数据库
    • MySQL
      • 大众点评订单系统分库分表实践
  • 数据库
    • MySQL
      • 如何保证缓存与数据库双写时的数据一致性?
  • 数据库
    • MySQL
      • 浅谈数据库并发控制 - 锁和 MVCC
  • 数据库
    • MySQL
      • 深入浅出MySQL 中事务的实现
  • 数据库
    • MySQL
      • 浅入浅出MySQL 和 InnoDB
  • 数据库
    • PostgreSQL
      • PostgreSQL upsert功能(insert on conflict do)的用法
  • 数据库
    • Redis
      • Redis GEO & 实现原理深度分析
  • 数据库
    • Redis
      • Redis 和 I/O 多路复用
  • 数据库
    • Redis
      • Redis分布式锁
  • 数据库
    • Redis
      • Redis实现分布式锁中的“坑”
  • 数据库
    • Redis
      • Redis总结
  • 数据库
    • Redis
      • 史上最全Redis高可用技术解决方案大全
  • 数据库
    • Redis
      • Redlock:Redis分布式锁最牛逼的实现
  • 数据库
    • Redis
      • 为什么 Redis 选择单线程模型
  • 数据库
    • TiDB
      • 新一代数据库TiDB在美团的实践
  • 数据库
    • 数据仓库
      • 实时数仓在有赞的实践
  • 数据库
    • 数据库原理
      • OLTP与OLAP的关系是什么?
  • 数据库
    • 数据库原理
      • 为什么 OLAP 需要列式存储
  • 系统设计
    • DDD
      • Domain Primitive
  • 系统设计
    • DDD
      • Repository模式
  • 系统设计
    • DDD
      • 应用架构
  • 系统设计
    • DDD
      • 聊聊如何避免写流水账代码
  • 系统设计
    • DDD
      • 领域层设计规范
  • 系统设计
    • DDD
      • 从三明治到六边形
  • 系统设计
    • DDD
      • 阿里盒马领域驱动设计实践
  • 系统设计
    • DDD
      • 领域驱动设计(DDD)编码实践
  • 系统设计
    • DDD
      • 领域驱动设计在互联网业务开发中的实践
  • 系统设计
    • 基础架构
      • 容错,高可用和灾备
  • 系统设计
    • 数据聚合
      • GraphQL及元数据驱动架构在后端BFF中的实践
  • 系统设计
    • 数据聚合
      • 高效研发-闲鱼在数据聚合上的探索与实践
  • 系统设计
    • 服务安全
      • JSON Web Token 入门教程
  • 系统设计
    • 服务安全
      • 你还在用JWT做身份认证嘛?
  • 系统设计
    • 服务安全
      • 凭证(Credentials)
  • 系统设计
    • 服务安全
      • 授权(Authorization)
  • 系统设计
    • 服务安全
      • 理解OAuth2.0
  • 系统设计
    • 服务安全
      • 认证(Authentication)
  • 系统设计
    • 架构案例
      • 微信 Android 客户端架构演进之路
  • 系统设计
    • 高可用架构
      • 业务高可用的保障:异地多活架构
  • 计算机基础
    • 字符编码
      • Base64原理解析
  • 计算机基础
    • 字符编码
      • 字符编码笔记:ASCII,Unicode 和 UTF-8
  • 计算机基础
    • 操作系统
      • 为什么 CPU 访问硬盘很慢
  • 计算机基础
    • 操作系统
      • 为什么 HTTPS 需要 7 次握手以及 9 倍时延
  • 计算机基础
    • 操作系统
      • 为什么 Linux 默认页大小是 4KB
  • 计算机基础
    • 操作系统
      • 磁盘IO那些事
  • 计算机基础
    • 操作系统
      • 虚拟机的3种网络模式
  • 计算机基础
    • 服务器
      • mac终端bash、zsh、oh-my-zsh最实用教程
  • 计算机基础
    • 服务器
      • Nginx强制跳转Https
  • 计算机基础
    • 服务器
      • curl 的用法指南
  • 计算机基础
    • 网络安全
      • 如何设计一个安全的对外接口?
  • 计算机基础
    • 网络安全
      • 浅谈常见的七种加密算法及实现
  • 计算机基础
    • 网络编程
      • MQTT - The Standard for IoT Messaging
  • 计算机基础
    • 网络编程
      • 两万字长文 50+ 张趣图带你领悟网络编程的内功心法
  • 计算机基础
    • 网络编程
      • 为什么 TCP 协议有 TIME_WAIT 状态
  • 计算机基础
    • 网络编程
      • 为什么 TCP 协议有性能问题
  • 计算机基础
    • 网络编程
      • 为什么 TCP 协议有粘包问题
  • 计算机基础
    • 网络编程
      • 为什么 TCP 建立连接需要三次握手
  • 计算机基础
    • 网络编程
      • 为什么 TCP/IP 协议会拆分数据
  • 计算机基础
    • 网络编程
      • 使用 OAuth 2 和 JWT 为微服务提供安全保障
  • 计算机基础
    • 网络编程
      • 四种常见的 POST 提交数据方式
  • 计算机基础
    • 网络编程
      • 有赞TCP网络编程最佳实践
  • 计算机基础
    • 网络编程
      • 看完这篇HTTP,跟面试官扯皮就没问题了
  • 计算机基础
    • 网络编程
      • 详细解析 HTTP 与 HTTPS 的区别
  • 质量&效率
    • 快捷键
      • Idea快捷键(Mac版)
  • 质量&效率
    • 快捷键
      • Shell快捷键
  • 质量&效率
    • 快捷键
      • conduit
  • 质量&效率
    • 敏捷开发
      • Scrum的3种角色
  • 质量&效率
    • 敏捷开发
      • Scrum的4种会议
  • 质量&效率
    • 敏捷开发
      • ThoughtWorks的敏捷开发
  • 质量&效率
    • 敏捷开发
      • 敏捷开发入门教程
  • 运维&测试
    • Docker
      • Docker (容器) 的原理
  • 运维&测试
    • Docker
      • Docker Compose:链接外部容器的几种方式
  • 运维&测试
    • Docker
      • Docker 入门教程
  • 运维&测试
    • Docker
      • Docker 核心技术与实现原理
  • 运维&测试
    • Docker
      • Dockerfile 最佳实践
  • 运维&测试
    • Docker
      • Docker开启Remote API 访问 2375端口
  • 运维&测试
    • Docker
      • Watchtower - 自动更新 Docker 镜像与容器
  • 运维&测试
    • Kubernetes
      • Kubernetes 介绍
  • 运维&测试
    • Kubernetes
      • Kubernetes 在有赞的实践
  • 运维&测试
    • Kubernetes
      • Kubernetes 学习路径
  • 运维&测试
    • Kubernetes
      • Kubernetes如何改变美团的云基础设施?
  • 运维&测试
    • Kubernetes
      • Kubernetes的三种外部访问方式:NodePort、LoadBalancer 和 Ingress
  • 运维&测试
    • Kubernetes
      • 谈 Kubernetes 的架构设计与实现原理
  • 运维&测试
    • 压测
      • 全链路压测平台(Quake)在美团中的实践
  • 运维&测试
    • 测试
      • Cpress - JavaScript End to End Testing Framework
  • 运维&测试
    • 测试
      • 代码覆盖率-JaCoCo
  • 运维&测试
    • 测试
      • 浅谈代码覆盖率
  • 运维&测试
    • 测试
      • 测试中 Fakes、Mocks 以及 Stubs 概念明晰
  • Java FrameWorks
    • Spring
      • Spring AOP
        • Spring AOP中的Bean是如何被AOP代理的
  • Java FrameWorks
    • Spring
      • Spring AOP
        • Spring AOP原生动态代理和Cglib动态代理
  • Java FrameWorks
    • Spring
      • Spring AOP
        • Spring AOP实现方式(xml&注解)
  • Java FrameWorks
    • Spring
      • Spring AOP
        • Spring AOP是如何收集切面类并封装的
  • Java FrameWorks
    • Spring
      • Spring AOP
        • Spring AOP概述
  • Java FrameWorks
    • Spring
      • Spring AOP
        • Spring AOP的底层核心后置处理器
  • Java FrameWorks
    • Spring
      • Spring AOP
        • Spring AOP的延伸知识
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot - IOC(一)
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot - IOC(三)
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot - IOC(二)
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot - IOC(五)
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot - IOC(四) - 循环依赖与解决方案
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot - 启动引导
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot JarLauncher
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot Web Mvc 自动装配
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot 使用ApplicationListener监听器
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot 声明式事务
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot 嵌入式容器
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot引起的“堆外内存泄漏”排查及经验总结
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot的启动流程
  • Java FrameWorks
    • Spring
      • Spring Boot
        • Spring Boot自动化配置源码分析
  • Java FrameWorks
    • Spring
      • Spring Boot
        • 如何自定义Spring Boot Starter?
  • Java FrameWorks
    • Spring
      • Spring IOC
        • IOC - 模块装配和条件装配
  • Java FrameWorks
    • Spring
      • Spring IOC
        • IOC - 配置源(xml,注解)
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring Environment
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring ApplicationContext
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring BeanDefinition
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring BeanFactory
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring BeanFactoryPostProcessor
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring BeanPostProcessor
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring Bean的生命周期(一) - 概述
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring Bean的生命周期(三) - 实例化阶段
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring Bean的生命周期(二) - BeanDefinition
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring Bean的生命周期(五) - 销毁阶段
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring Bean的生命周期(四) - 初始化阶段
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring ComponentScan
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring Events
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring IOC 基础篇
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring IOC 总结
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring IOC 进阶篇
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring IOC容器的生命周期
  • Java FrameWorks
    • Spring
      • Spring IOC
        • Spring Resource
  • Java FrameWorks
    • Spring
      • Spring MVC
        • DispatcherServlet的初始化原理
  • Java FrameWorks
    • Spring
      • Spring MVC
        • DispatcherServlet的核心工作原理
  • Java FrameWorks
    • Spring
      • Spring MVC
        • WebMvc的架构设计与组件功能解析
  • Java FrameWorks
    • Spring
      • Spring Security
        • Spring Boot 2 + Spring Security 5 + JWT 的单页应用 Restful 解决方案
  • Java FrameWorks
    • Spring
      • Spring Security
        • Spring Security Oauth
  • Java FrameWorks
    • Spring
      • Spring Security
        • Spring Security
  • Java FrameWorks
    • Spring
      • Spring WebFlux
        • DispatcherHandler的工作原理(传统方式)
  • Java FrameWorks
    • Spring
      • Spring WebFlux
        • DispatcherHandler的工作原理(函数式端点)
  • Java FrameWorks
    • Spring
      • Spring WebFlux
        • WebFlux的自动装配
  • Java FrameWorks
    • Spring
      • Spring WebFlux
        • 快速了解响应式编程与Reactive
  • Java FrameWorks
    • Spring
      • Spring WebFlux
        • 快速使用WebFlux
  • 分布式
    • 协调服务
      • Zookeeper
        • Zookeeper - 客户端之 Curator
  • 分布式
    • 协调服务
      • Zookeeper
        • 详解分布式协调服务 ZooKeeper
  • 分布式
    • 协调服务
      • etcd
        • 高可用分布式存储 etcd 的实现原理
  • 数据库
    • Database Version Control
      • Flyway
        • Database Migrations with Flyway
  • 数据库
    • Database Version Control
      • Flyway
        • How Flyway works
  • 数据库
    • Database Version Control
      • Flyway
        • Rolling Back Migrations with Flyway
  • 数据库
    • Database Version Control
      • Flyway
        • The meaning of the concept of checksums
  • 数据库
    • Database Version Control
      • Liquibase
        • Introduction to Liquibase Rollback
  • 数据库
    • Database Version Control
      • Liquibase
        • LiquiBase中文学习指南
  • 数据库
    • Database Version Control
      • Liquibase
        • Use Liquibase to Safely Evolve Your Database Schema
  • 系统设计
    • 流量控制
      • RateLimiter
        • Guava Rate Limiter实现分析
  • 系统设计
    • 流量控制
      • Sentinel
        • Sentinel 与 Hystrix 的对比
  • 系统设计
    • 流量控制
      • Sentinel
        • Sentinel工作主流程
  • 系统设计
    • 流量控制
      • 算法
        • 分布式服务限流实战
  • 系统设计
    • 解决方案
      • 秒杀系统
        • 如何设计一个秒杀系统
  • 系统设计
    • 解决方案
      • 红包系统
        • 微信高并发资金交易系统设计方案--百亿红包背后的技术支撑
  • 计算机基础
    • 数据结构与算法
      • 其他相关
        • 什么是预排序遍历树算法(MPTT,Modified Preorder Tree Traversal)
  • 计算机基础
    • 数据结构与算法
      • 其他相关
        • 加密算法
  • 计算机基础
    • 数据结构与算法
      • 其他相关
        • 推荐系统算法
  • 计算机基础
    • 数据结构与算法
      • 其他相关
        • linkerd
  • 计算机基础
    • 数据结构与算法
      • 其他相关
        • 查找算法
  • 计算机基础
    • 数据结构与算法
      • 其他相关
        • 缓存淘汰算法中的LRU和LFU
  • 计算机基础
    • 数据结构与算法
      • 其他相关
        • 负载均衡算法
  • 计算机基础
    • 数据结构与算法
      • 分布式算法
        • 分布式算法 - Paxos算法
  • 计算机基础
    • 数据结构与算法
      • 分布式算法
        • 分布式算法 - Raft算法
  • 计算机基础
    • 数据结构与算法
      • 分布式算法
        • 分布式算法 - Snowflake算法
  • 计算机基础
    • 数据结构与算法
      • 分布式算法
        • 分布式算法 - ZAB算法
  • 计算机基础
    • 数据结构与算法
      • 分布式算法
        • 分布式算法 - 一致性Hash算法
  • 计算机基础
    • 数据结构与算法
      • 大数据处理
        • 大数据处理 - Bitmap & Bloom Filter
  • 计算机基础
    • 数据结构与算法
      • 大数据处理
        • 大数据处理 - Map & Reduce
  • 计算机基础
    • 数据结构与算法
      • 大数据处理
        • 大数据处理 - Trie树/数据库/倒排索引
  • 计算机基础
    • 数据结构与算法
      • 大数据处理
        • 大数据处理 - 分治/hash/排序
  • 计算机基础
    • 数据结构与算法
      • 大数据处理
        • 大数据处理 - 双层桶划分
  • 计算机基础
    • 数据结构与算法
      • 大数据处理
        • 大数据处理 - 外(磁盘文件)排序
  • 计算机基础
    • 数据结构与算法
      • 大数据处理
        • 大数据处理 - 布隆过滤器
  • 计算机基础
    • 数据结构与算法
      • 大数据处理
        • 大数据处理算法
  • 计算机基础
    • 数据结构与算法
      • 字符串匹配算法
        • 字符串匹配 - 文本预处理:后缀树(Suffix Tree)
  • 计算机基础
    • 数据结构与算法
      • 字符串匹配算法
        • 字符串匹配 - 模式预处理:BM 算法 (Boyer-Moore)
  • 计算机基础
    • 数据结构与算法
      • 字符串匹配算法
        • 字符串匹配 - 模式预处理:KMP 算法(Knuth-Morris-Pratt)
  • 计算机基础
    • 数据结构与算法
      • 字符串匹配算法
        • 字符串匹配 - 模式预处理:朴素算法(Naive)(暴力破解)
  • 计算机基础
    • 数据结构与算法
      • 字符串匹配算法
        • 字符串匹配
  • 计算机基础
    • 数据结构与算法
      • 常用算法
        • 分支限界算法
  • 计算机基础
    • 数据结构与算法
      • 常用算法
        • 分治算法
  • 计算机基础
    • 数据结构与算法
      • 常用算法
        • 动态规划算法
  • 计算机基础
    • 数据结构与算法
      • 常用算法
        • 回溯算法
  • 计算机基础
    • 数据结构与算法
      • 常用算法
        • 贪心算法
  • 计算机基础
    • 数据结构与算法
      • 排序算法
        • 十大排序算法
  • 计算机基础
    • 数据结构与算法
      • 排序算法
        • 图解排序算法(一)之3种简单排序(选择,冒泡,直接插入)
  • 计算机基础
    • 数据结构与算法
      • 排序算法
        • 图解排序算法(三)之堆排序
  • 计算机基础
    • 数据结构与算法
      • 排序算法
        • 图解排序算法(二)之希尔排序
  • 计算机基础
    • 数据结构与算法
      • 排序算法
        • 图解排序算法(四)之归并排序
  • 计算机基础
    • 数据结构与算法
      • 数据结构
        • 树的高度和深度
  • 计算机基础
    • 数据结构与算法
      • 数据结构
        • 红黑树深入剖析及Java实现
  • 计算机基础
    • 数据结构与算法
      • 数据结构
        • 线性结构 - Hash
  • 计算机基础
    • 数据结构与算法
      • 数据结构
        • 线性结构 - 数组、链表、栈、队列
  • 计算机基础
    • 数据结构与算法
      • 数据结构
        • 逻辑结构 - 树
  • 运维&测试
    • 测试
      • Spock
        • Groovy 简明教程
  • 运维&测试
    • 测试
      • Spock
        • Spock 官方文档
  • 运维&测试
    • 测试
      • Spock
        • Spock单元测试框架介绍以及在美团优选的实践
  • 运维&测试
    • 测试
      • TDD
        • TDD 实践 - FizzFuzzWhizz(一)
  • 运维&测试
    • 测试
      • TDD
        • TDD 实践 - FizzFuzzWhizz(三)
  • 运维&测试
    • 测试
      • TDD
        • TDD 实践 - FizzFuzzWhizz(二)
  • 运维&测试
    • 测试
      • TDD
        • 测试驱动开发(TDD)- 原理篇
  • 微服务
    • Spring Cloud
      • Spring Cloud Alibaba
        • Nacos
          • Nacos 服务注册的原理
  • 微服务
    • Spring Cloud
      • Spring Cloud Alibaba
        • Nacos
          • Nacos 配置中心原理分析
  • 微服务
    • Spring Cloud
      • Spring Cloud Alibaba
        • Seata
          • 服务调用过程
  • 微服务
    • Spring Cloud
      • Spring Cloud Alibaba
        • Seata
          • Spring Cloud Bus
  • 微服务
    • Spring Cloud
      • Spring Cloud Alibaba
        • Seata
          • Spring Cloud Consul
  • 微服务
    • Spring Cloud
      • Spring Cloud Alibaba
        • Seata
          • Spring Cloud Stream
  • 微服务
    • Spring Cloud
      • Spring Cloud Alibaba
        • Sentinel
          • Sentinel 与 Hystrix 的对比
  • 微服务
    • Spring Cloud
      • Spring Cloud Alibaba
        • Sentinel
          • Sentinel
  • 微服务
    • Spring Cloud
      • Spring Cloud Netflix
        • Hystrix
          • How Hystrix Works
  • 微服务
    • Spring Cloud
      • Spring Cloud Netflix
        • Hystrix
          • Hystrix
  • 微服务
    • Spring Cloud
      • Spring Cloud Netflix
        • Hystrix
          • Hystrix原理与实战
  • 微服务
    • Spring Cloud
      • Spring Cloud Netflix
        • Hystrix
          • Spring Cloud Hystrix基本原理
由 GitBook 提供支持
在本页
  • 1. AbstractApplicationContext#refresh
  • 1.1 prepareRefresh - 初始化前的预处理
  • 1.2 obtainFreshBeanFactory - 初始化BeanFactory
  • 1.3 prepareBeanFactory - BeanFactory的预处理动作
  • 1.4 postProcessBeanFactory - BeanFactory的后置处理
  • 1.5 invokeBeanFactoryPostProcessors - 执行BeanFactoryPostProcessor
  • 1.6 registerBeanPostProcessors - 初始化BeanPostProcessor
  • 1.7 initMessageSource - 初始化国际化组件
  • 1.8 initApplicationEventMulticaster - 初始化事件广播器
  • 1.9 onRefresh - 子类扩展的刷新动作
  • 1.10 registerListeners - 注册监听器
  • 1.11 finishBeanFactoryInitialization - 初始化剩余的单实例bean
  • 1.12 finishRefresh - 刷新后的动作
  • 1.13 resetCommonCaches - 清除缓存
  • 1.14 小结
  • 2. ApplicationContext初始化中的扩展点
  • 2.1 invokeBeanFactoryPostProcessors
  • 2.2 registerBeanPostProcessors
  • 2.3 finishBeanFactoryInitialization

这有帮助吗?

  1. Java FrameWorks
  2. Spring
  3. Spring IOC

Spring IOC容器的生命周期

前面我们已经研究了 Bean 的完整生命周期,在此期间我们也对整个 IOC 容器的生命周期了解了部分流程。本章咱来完整的看一下 IOC 容器的一个刷新动作中,会有哪些动作的触发,以及从这些流程中,我们能梳理出哪些可以切入进 SpringFramework 内部流程的扩展点。

本章主要涉及的原理部分:

  • ApplicationContext#refresh 方法整体概述

  • refresh 方法中可以切入的扩展点

好了我们开始,前面我们已经反复多次提到 ApplicationContext 的 refresh 方法是整个 IOC 容器初始化的核心,它一共分为 13 步:

1. AbstractApplicationContext#refresh

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        // 1. 初始化前的预处理
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        // 2. 获取BeanFactory,加载所有bean的定义信息(未实例化)
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        // 3. BeanFactory的预处理配置
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            // 4. 准备BeanFactory完成后进行的后置处理
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            // 5. 执行BeanFactory创建后的后置处理器
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            // 6. 注册Bean的后置处理器
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            // 7. 初始化MessageSource
            initMessageSource();

            // Initialize event multicaster for this context.
            // 8. 初始化事件派发器
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            // 9. 子类的多态onRefresh
            onRefresh();

            // Check for listener beans and register them.
            // 10. 注册监听器
            registerListeners();
          
            //到此为止,BeanFactory已创建完成

            // Instantiate all remaining (non-lazy-init) singletons.
            // 11. 初始化所有剩下的单例Bean
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            // 12. 完成容器的创建工作
            finishRefresh();
        } // catch ......

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            // 13. 清除缓存
            resetCommonCaches();
        }
    }
}

本章我们重点研究的,是这里面每一步都做了哪些事情,对于里面涉及的细节不作过多研究,感兴趣的小伙伴可以移步 boot 小册第 11 - 15 章。

考虑到部分方法的实现中涉及到的源码和注释会很多,会很影响阅读体验,小册只会截取关键步骤的关键源码进行解读。

1.1 prepareRefresh - 初始化前的预处理

protected void prepareRefresh() {
    // 此处会记录启动时间,切换IOC容器的状态
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);

    // logger ......

    // 初始化属性配置
    initPropertySources();

    // 属性校验
    getEnvironment().validateRequiredProperties();

    // 省略源码 - 初始化早期事件
}

这一步中,大多数的动作都是前置性的准备,而且基本上这些准备的动作在我们现阶段学习的内容中几乎都用不到,小伙伴们可以暂且忽略即可。

initPropertySources 方法在基于 web 环境的 ApplicationContext 子类中有重写,在 boot 小册的第 11 章中有提及到,感兴趣的小伙伴们可以先去看一看。

关于早期事件的概念,可能现阶段解释起来比较复杂,后续再考虑补充。

1.2 obtainFreshBeanFactory - 初始化BeanFactory

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    return getBeanFactory();
}

基于 xml 配置文件的 ApplicationContext 中,在该步骤会解析 xml 配置文件,封装 BeanDefinition 。但是,基于注解配置类的 ApplicationContext 就不太一样了,上一章中我们看到,GenericApplicationContext 的 refreshBeanFactory 方法中,有一个 CAS 判断的动作,它控制着 GenericApplicationContext 不能反复刷新。所以从这一步我们能知道的,是基于 xml 配置文件的 **ApplicationContext** 可以反复刷新,基于注解配置类的 **ApplicationContext** 只能刷新一次。

1.3 prepareBeanFactory - BeanFactory的预处理动作

这个方法比较长,但仔细观察可以发现源码是非常有条理的:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 给BeanFactory中设置类加载器、表达式解析器
    beanFactory.setBeanClassLoader(getClassLoader());
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // 1.3.1 编码注册ApplicationContextAwareProcessor
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    // 1.3.2 以下几个Aware接口的回调注入不由BeanFactory负责
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // 1.3.3 以下几个类型的自动注入会直接绑定
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // 又编码注册监听器钩子
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // 又是Load Time Weaver相关的部分,AOP再解释
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // Set a temporary ClassLoader for type matching.
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // 注册默认的运行时环境Environment
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}

这部分很好理解吧!不过这个方法内信息量有点大,我们有必要研究一下。

1.3.1 ApplicationContextAwareProcessor的注册

在 Aware 接口注入的后置处理器中,那个起核心作用的 ApplicationContextAwareProcessor 是在此处注册的,而且它负责注入的 6 个 Aware 接口,恰好就是上面源码中忽略的 6 个接口,也证实了 ApplicationContextAwareProcessor 接管 BeanFactory 自动注入这一设计。

如何理解这一设计:BeanFactory 来自 spring-beans 包,而 ApplicationContext 来自 spring-context 包。由于 context 依赖 beans ,而 beans 本身可以单独存在。在没有 context 包的环境下,BeanFactory 本身也可以作为一个普通的 IOC 容器来处理依赖查找和自动类型注入,而引入 context 包后,出现了更多的内部组件,注入的要求也就更复杂。本着单一职责与职责分离的原则,BeanFactory 还是干原来的事情,扩展的 Aware 回调注入则交给 context 包中的 ApplicationContextAwareProcessor 搞定。

1.3.2 ignoreDependencyInterface的设计

既然有 6 个 Aware 回调接口的工作被 ApplicationContextAwareProcessor 接管了,那 BeanFactory 本身就不再需要考虑这 6 个接口的注入了。这 6 个接口最终会存储到 AbstractAutowireCapableBeanFactory 的 ignoredDependencyInterfaces 变量中:

private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<>();

而它被利用的时机,是在 bean 生命周期中的属性赋值 populateBean 阶段:

    // ......
    if (needsDepCheck) {
        if (filteredPds == null) {
            // 此处ignoreDependencyInterface会被利用
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        }
        checkDependencies(beanName, mbd, filteredPds, pvs);
    }

    if (pvs != null) {
        // 将PropertyValues应用给bean
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

这个源码片段是不是很熟悉呀,在第 35 章中,我们讲解 applyPropertyValues 方法,就是截取了这一小段,而上面露头的 filterPropertyDescriptorsForDependencyCheck 方法,内部就使用了 ignoredDependencyInterfaces 这个集合检查那些依赖的 Aware 接口。

这里多说一嘴 Aware 接口在没有被 BeanFactory 忽略掉的执行原则吧。通常来讲,Aware 接口都会定义一个 setXXX 的方法(如 BeanFactoryAware 接口的 setBeanFactory 方法),同时实现了 Aware 接口的方法通常都会在成员属性中定义一个与回调注入类型相同的属性变量(如实现了 BeanFactoryAware 接口的类,通常都会定义一个 private BeanFactory beanFactory; )。如果是按照这种设计编写的代码,BeanFactory 会认定这个属性可以受自动注入的支持( autowire-mode ),并对这个属性进行依赖注入。简单的讲,**BeanFactory** 可以支持的自动注入的属性必须带有 setter 方法,而 **Aware** 接口的方法定义风格刚好是 setter 的风格,所以只需要求实现了 **Aware** 接口的类,定义属性时,属性名与 setter 方法对应的名称一致即可( setPerson → person )。

1.3.3 registerResolvableDependency的设计

这个 registerResolvableDependency 方法,可能小伙伴们看了源码之后会更容易理解:

// Map from dependency type to corresponding autowired value.
// 从依赖属性的类型映射到相应的自动装配值
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);

public void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue) {
    Assert.notNull(dependencyType, "Dependency type must not be null");
    if (autowiredValue != null) {
        // check throw ex ......
        this.resolvableDependencies.put(dependencyType, autowiredValue);
    }
}

是不是一下子就看明白了,调用这个方法后,在 BeanFactory 再遇到特定类型的属性注入时,会直接从这个 resolvableDependencies 的 Map 中找出对应的值,直接注入进去(相当于预先指定好了哪个类型注入哪个值,不需要额外考虑)。

1.4 postProcessBeanFactory - BeanFactory的后置处理

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}

这个方法在 AbstractApplicationContext 中是一个模板方法,它的重写在基于 web 环境的 ApplicationContext 子类中有实现,回头我们学到 WebMvc 章节中再来看它。

1.5 invokeBeanFactoryPostProcessors - 执行BeanFactoryPostProcessor

这个方法我们前面已经看过了,它会执行所有的 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor ,主要工作是包扫描、解析配置类等,不再赘述。

1.6 registerBeanPostProcessors - 初始化BeanPostProcessor

这个方法我们前面也看过了,它会把所有的 BeanPostProcessor 都注册到位,这里面的处理逻辑与上面的 invokeBeanFactoryPostProcessors 类似,忘记的小伙伴们记得看前面第 34 章哦。

1.7 initMessageSource - 初始化国际化组件

这个方法的源码小册不在此处贴出,它涉及到国际化的知识。早在第 15 章我们就说过,国际化的内容小册会放到 WebMvc 章节中讲解,so 此处先留下一个坑,回头到了 WebMvc 中再填。

1.8 initApplicationEventMulticaster - 初始化事件广播器

protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        // logger ......
    }
    else {
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        // logger ......
    }
}

这部分的内容非常简单了,它会构造一个 SimpleApplicationEventMulticaster ,并注册进 BeanFactory 中,仅此而已。

1.9 onRefresh - 子类扩展的刷新动作

protected void onRefresh() throws BeansException {
    // For subclasses: do nothing by default.
}

1.10 registerListeners - 注册监听器

protected void registerListeners() {
    // 注册所有已经被创建出来的ApplicationListener,绑定到ApplicationEventMulticaster中
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    // 此处不会实例化ApplicationListener,而是只绑定name
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // 广播早期事件(后续再解释)
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

这个方法共分为三个小段,条理也非常清晰。不过要注意一点,此处那些没有初始化的 ApplicationListener 并没有被实例化,而是会等到下一步 finishBeanFactoryInitialization 方法中才会被创建出来(注释中也说了,不要在此处创建,因为框架希望让那些后置处理器去干预它们)。

1.11 finishBeanFactoryInitialization - 初始化剩余的单实例bean

这个方法就是一个一个的循环初始化那些非延迟加载的单实例 bean 了,整个流程我们已经在第 34 、35 章讲过了,这里不再赘述。

1.12 finishRefresh - 刷新后的动作

protected void finishRefresh() {
    // Clear context-level resource caches (such as ASM metadata from scanning).
    // 清除上下文级别的资源缓存
    clearResourceCaches();

    // Initialize lifecycle processor for this context.
    // 为当前ApplicationContext初始化一个生命周期处理器
    initLifecycleProcessor();

    // Propagate refresh to lifecycle processor first.
    // 将refresh的动作传播到生命周期处理器
    getLifecycleProcessor().onRefresh();

    // Publish the final event.
    // 广播事件
    publishEvent(new ContextRefreshedEvent(this));

    // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}

这个方法小册在第 35 章也讲到过了,它主要是初始化 LifecycleProcessor 、广播刷新完成的事件,整体也没什么难的。

1.13 resetCommonCaches - 清除缓存

protected void resetCommonCaches() {
    ReflectionUtils.clearCache();
    AnnotationUtils.clearCache();
    ResolvableType.clearCache();
    CachedIntrospectionResults.clearClassLoader(getClassLoader());
}

这就没啥好说的了吧,这些乱七八糟的缓存都可以干掉了,因为准备工作都完成了。

1.14 小结

纵观整个 refresh 方法,每个动作的职责都很清晰,而且非常的有条理性。这个过程中,有对 BeanFactory 的处理,有对 ApplicationContext 的处理,有处理 BeanPostProcessor 的逻辑,有准备 ApplicationListener 的逻辑,最后它会初始化那些非延迟加载的单实例 bean 。整个 refresh 方法走下来,ApplicationContext 也就全部初始化完毕了。

2. ApplicationContext初始化中的扩展点

看了上面的整个逻辑,想必小伙伴们也比较清楚的理解 ApplicationContext 中的初始化逻辑了。IOC 原理的最后一个部分,我们来梳理一下,整个 ApplicationContext 的初始化逻辑中,都有哪些扩展点可供我们切入利用。清楚地理解这些扩展点,可以让我们在后续扩展 Spring 时更加容易和游刃有余。

一般情况下,我们不会在 ApplicationContext 的初始化和 refresh 动作之间作太多的处理,主要还是从 refresh 方法本身出发考虑,故以下梳理的扩展点都来自于 refresh 方法开始触发时。

2.1 invokeBeanFactoryPostProcessors

前四个方法中,在普通的 ApplicationContext 下都无法切入,所以只能在第 5 步 invokeBeanFactoryPostProcessors 方法中切入了。而这个方法中可供切入的点实在是太多了,咱一一来数。

2.1.1 ImportSelector&ImportBeanDefinitionRegistrar

咦,没想到吧,第一个竟然不是 BeanFactoryPostProcessor 或者BeanDefinitionRegistryPostProcessor ,原因是它们的执行时机通常都在 ConfigurationClassPostProcessor 之后啦,而 **ConfigurationClassPostProcessor** 的执行过程中,会解析 **@Import** 注解,取出里面的 **ImportBeanDefinitionRegistrar** 并执行,所以第一个扩展点是 ImportSelector 和 ImportBeanDefinitionRegistrar 了。

ImportSelector 在该阶段只能拿到当前 @Import 标注的注解配置类的信息(如下面代码中 BarImportSelector 只能拿到 BarConfiguration 的信息)

@Import(BarImportSelector.class)
@Configuration
public class BarConfiguration { ... }

ImportBeanDefinitionRegistrar 在该阶段除了可以获取到当前 @Import 标注的注解配置类的信息之外,更重要的是能拿到 BeanDefinitionRegistry ,由此可供扩展的动作主要是给 BeanDefinitionRegistry 中注册新的 BeanDefinition 。

不过小伙伴如果把 BeanDefinitionRegistry 看做 DefaultListableBeanFactory 也不是不行,只是说考虑到依赖倒转的设计,此处还是拿接口比较合适。

2.1.2 BeanDefinitionRegistryPostProcessor

这个切入算是比较简单明了的吧,前面我们也已经学过了,使用 BeanDefinitionRegistryPostProcessor 可以拿到 BeanDefinitionRegistry 的 API ,直接向 IOC 容器中注册新的 BeanDefinition 。

不过这里面有一点要注意,刚才上面也提到了,一般情况下,自定义的 **BeanDefinitionRegistryPostProcessor** 执行时机比内置的 **ConfigurationClassPostProcessor** 要晚,这也是 SpringFramework 最开始的设计( ConfigurationClassPostProcessor 实现了 PriorityOrdered 接口,这个接口的优先级最高)。

注意上面的话说的是 “一般情况下” 哦,说明小册有留台阶的。如果小伙伴们非要让自己写的 BeanDefinitionRegistryPostProcessor 执行时机比 ConfigurationClassPostProcessor 早,可以让后置处理器实现 **PriorityOrdered** 接口,声明较高执行优先级(不能是 **Ordered.LOWEST_PRECEDENCE** ,否则排序规则会变成字母表顺序)。经过这样的设计之后,自定义的 BeanDefinitionRegistryPostProcessor 就可以在 ConfigurationClassPostProcessor 之前执行了。

2.1.3 BeanFactoryPostProcessor

BeanFactoryPostProcessor 的切入时机紧随 BeanDefinitionRegistryPostProcessor 之后,本来它没什么好说的了,小伙伴们只需要注意一下,在 BeanFactoryPostProcessor 的切入回调中,可以拿到的参数是 ConfigurableListableBeanFactory ,拿到它就意味着,我们在这个阶段按理来讲不应该再向 BeanFactory 中注册新的 BeanDefinition 了,只能获取和修改现有的 BeanDefinition 。

另外,还要注意一点,javadoc 中有说,BeanFactoryPostProcessor 的处理阶段是可以提早初始化 bean 对象的,因为这个阶段下只有 ApplicationContextAwareProcessor 注册到了 BeanFactory 中,没有其余关键的 BeanPostProcessor ,所以这个阶段初始化的 bean 有一个共同的特点:能使用 **Aware** 回调注入,但无法使用 **@Autowired** 等自动注入的注解进行依赖注入,且不会产生任何代理对象。

2.2 registerBeanPostProcessors

所有 BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 都处理完之后,下一步是初始化 BeanPostProcessor 。这个逻辑我们之前也都看过了,但这个阶段没有可以切入影响该阶段的时机,所以该阶段跳过。

2.3 finishBeanFactoryInitialization

一下子就来到最复杂的初始化 bean 的这一步了。这里面的切入时机才多呢,前面看 bean 的实例化和初始化过程中,有非常多可供切入的时机,我们逐个来看。

本方法中涉及到的所有切入点均为针对单个 bean 的扩展。

2.3.1 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation

从 bean 的创建阶段之前,就有 InstantiationAwareBeanPostProcessor 来拦截创建了,每个 bean 在创建之前都会尝试着使用 InstantiationAwareBeanPostProcessor 来代替创建,如果没有任何 InstantiationAwareBeanPostProcessor 可以拦截创建,则会走真正的 bean 对象实例化流程。

在 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法中,只能拿到 bean 对应的 Class 类型,以及 bean 的名称(当然啦,本来就是凭空造,有 Class 类型就够了),如果方法没有返回值,则代表 InstantiationAwareBeanPostProcessor 不参与拦截 bean 创建的动作。

2.3.2 SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors

如果在实例化 bean 之前,InstantiationAwareBeanPostProcessor 没有起到作用,就会通过构造器创建对象。如果一个 bean 有多个构造器,如何选择合适的构造器去创建对象就是很重要的一步。在 34 章 2.4.4 节我们看到,筛选构造器的核心方法是 determineConstructorsFromBeanPostProcessors ,它会在底层寻找所有 SmartInstantiationAwareBeanPostProcessor ,回调 determineCandidateConstructors 方法获取可选择的构造器:

protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
        throws BeansException {
    if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
                if (ctors != null) {
                    return ctors;
                }
            }
        }
    }
    return null;
}

在第 27 章中我们就说过这个 SmartInstantiationAwareBeanPostProcessor 的使用了,如果在这里打入 Debug 断点时,程序代码运行时可以停在断点,但不会有任何返回,这个现象的产因是:默认情况下 ConfigurationClassPostProcessor 会向 IOC 容器注册一个 ImportAwareBeanPostProcessor ,但它又没有重写 determineCandidateConstructors 方法,就造成了这个现象。

所以一般情况下,SmartInstantiationAwareBeanPostProcessor 在 SpringFramework 内部是用不到的,我们平时开发不是特殊场景也用不上,这个小伙伴们知道一下就可以了。

2.3.3 MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition

在 createBeanInstance 方法执行完毕之后,此时 bean 对象已经创建出来了,只是没有任何属性值的注入而已。此时 doCreateBean 方法会走到 applyMergedBeanDefinitionPostProcessors 方法,让这些 MergedBeanDefinitionPostProcessor 去收集 bean 所属的 Class 中的注解信息。在第 35 章中小册有列出三个关键的 MergedBeanDefinitionPostProcessor ,它们分别是 InitDestroyAnnotationBeanPostProcessor (收集 @PostConstruct 与 @PreDestroy 注解)、CommonAnnotationBeanPostProcessor (收集 JSR 250 的其它注解)、AutowiredAnnotationBeanPostProcessor (收集自动注入相关的注解)。

在此处切入扩展,意味着可以对 bean 对象所属的 Class 作一些处理或者收集的动作(当然也可以进行属性赋值等动作,但考虑到职责分离,该步骤还是不要瞎搞为好 ~ ~)。

2.3.4 InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation

等这些 MergedBeanDefinitionPostProcessor 都工作完毕后,此时 bean 对象所属的 Class 中的信息都收集完毕了,接下来还得让 InstantiationAwareBeanPostProcessor 出场,它要负责控制是否继续走接下来的 populateBean 和 initializeBean 方法初始化 bean 。

所以如果在这里切入扩展的话,只能做到流程控制的作用。

2.3.5 InstantiationAwareBeanPostProcessor#postProcessProperties

又又又又又是它!不过这次它调用的是 postProcessProperties 方法,这个步骤会将 bean 对象对应的 PropertyValues 中封装赋值和注入的数据应用给 bean 实例。通常情况下,在该阶段 SpringFramework 内部起作用的后置处理器是 AutowiredAnnotationBeanPostProcessor ,它会搜集 bean 所属的 Class 中标注了 @Autowired 、@Value 、@Resource 等注解的属性和方法,并反射赋值 / 调用。

在此处扩展逻辑的话,相当于扩展了后置处理器的属性赋值 + 依赖注入的自定义逻辑。当这个动作执行完毕之后,就不会再有属性赋值和组件注入的回调了。

2.3.6 BeanPostProcessor

接下来的两个动作就发生在 initializeBean 方法中了,它就是 BeanPostProcessor 的前后两个执行动作 postProcessBeforeInitialization 和 postProcessAfterInitialization 。进入到 initializeBean 方法后,bean 的生命周期已经到了初始化逻辑回调的阶段,此时 bean 中应该注入的属性均已完备,BeanPostProcessor 的切入也只是给 bean 添加一些额外的属性的赋值、回调等等,以及生成代理对象。

所以,在此处切入扩展逻辑,相当于针对一个接近完善的 bean 去扩展 / 包装。当后置处理器执行完 postProcessAfterInitialization 方法后,基本上就代表 bean 的初始化结束了。

2.3.7 SmartInitializingSingleton

这个扩展在第 35 章我们有说过,它来自 SpringFramework 4.1 ,它是在所有非延迟加载的单实例 bean 全部初始化完成后才回调的。这个阶段底层会取出所有实现了 SmartInitializingSingleton 接口的 bean ,去回调 afterSingletonsInstantiated 方法。而且当时小册还说了,这个设计只是为了让 BeanFactory 也能插一脚初始化的后处理,仅此而已。

这个扩展是针对单个 bean 的, 不是切入所有 bean 的,所以严格意义上讲它属于 bean 初始化的扩展点。不过话又说回来,它是在 BeanFactory 把单实例 bean 都初始化完成后统一回调的,又属于一个整体动作,所以小册也就把它拿出来了。

上一页Spring IOC下一页Java FrameWorks

最后更新于2年前

这有帮助吗?

该部分又是一个模板方法,而它的扩展在纯 Spring 环境下是找不到的,不过在 SpringBoot 中,有子类对这个方法的重写,感兴趣的小伙伴可以移步 学习。

boot 小册第 16 章