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. ApplicationContext和它的上下辈们
  • 1.1⭐️ ApplicationContext
  • 1.2 ⭐️ConfigurableApplicationContext
  • 1.3 EnvironmentCapable
  • 1.4 MessageSource
  • 1.5 ApplicationEventPublisher
  • 1.6 ResourcePatternResolver
  • 2. ApplicationContext的实现类们
  • 2.1 ⭐️AbstractApplicationContex
  • 2.2 GenericApplicationContext
  • 2.3 AbstractRefreshableApplicationContext
  • 2.4 AbstractRefreshableConfigApplicationContext
  • 2.5 ⭐️AbstractXmlApplicationContext
  • 2.6 ClassPathXmlApplicationContext
  • 2.7 AnnotationConfigApplicationContext

这有帮助吗?

  1. Java FrameWorks
  2. Spring
  3. Spring IOC

Spring ApplicationContext

上一页Spring IOC下一页Java FrameWorks

最后更新于2年前

这有帮助吗?

之前说过推荐使用 ApplicationContext 而不是 BeanFactory ,因为 ApplicationContext 相比较 BeanFactory 扩展的实在是太多了:

Feature

BeanFactory

ApplicationContext

Bean instantiation/wiring —— Bean的实例化和属性注入

Yes

Yes

Integrated lifecycle management —— 生命周期管理

No

Yes

Automatic BeanPostProcessor registration —— Bean后置处理器的支持

No

Yes

Automatic BeanFactoryPostProcessor registration —— BeanFactory后置处理器的支持

No

Yes

Convenient MessageSource access (for internalization) —— 消息转换服务(国际化)

No

Yes

Built-in ApplicationEvent publication mechanism —— 事件发布机制(事件驱动)

No

Yes

1. ApplicationContext和它的上下辈们

img

可以发现 ApplicationContext 不仅继承了 BeanFactory 的两个扩展接口,还继承了其它几个接口,咱都一并来讲解。

1.1⭐️ ApplicationContext

1.1.1 ApplicationContext是SpringFramework最核心接口

Central interface to provide configuration for an application. This is read-only while the application is running, but may be reloaded if the implementation supports this.

它是为应用程序提供配置的中央接口。在应用程序运行时,它是只读的,但是如果受支持的话,它可以重新加载。

很言简意赅,ApplicationContext 就是中央接口,它就是 SpringFramework 的最最核心,同时在运行时是只读的。但是,另外它多提了一个概念:重新加载,这个概念很关键,咱会在后面介绍 ApplicationContext 的抽象实现中着重介绍它。

1.1.2 ApplicationContext组合多个功能接口

An ApplicationContext provides:

  • Bean factory methods for accessing application components. Inherited from ListableBeanFactory.

  • The ability to load file resources in a generic fashion. Inherited from the ResourceLoader interface.

  • The ability to publish events to registered listeners. Inherited from the ApplicationEventPublisher interface.

  • The ability to resolve messages, supporting internationalization. Inherited from the MessageSource interface.

  • Inheritance from a parent context. Definitions in a descendant context will always take priority. This means, for example, that a single parent context can be used by an entire web application, while each servlet has its own child context that is independent of that of any other servlet.

ApplicationContext 提供:

  • 用于访问应用程序组件的 Bean 工厂方法。继承自 ListableBeanFactory 。

  • 以通用方式加载文件资源的能力。继承自 ResourceLoader 接口。

  • 能够将事件发布给注册的监听器。继承自 ApplicationEventPublisher 接口。

  • 解析消息的能力,支持国际化。继承自 MessageSource 接口。

  • 从父上下文继承。在子容器中的定义将始终优先。例如,这意味着整个 Web 应用程序都可以使用单个父上下文,而每个 servlet 都有其自己的子上下文,该子上下文独立于任何其他 servlet 的子上下文。

这里面有一点需要注意,ApplicationContext 也是支持层级结构的,但这里它的描述是父子上下文,这个概念要区分理解。上下文中包含容器,但又不仅仅是容器。容器只负责管理 Bean ,但上下文中还包括动态增强、资源加载、事件监听机制等多方面扩展功能。

1.1.3 ApplicationContext负责部分回调注入

In addition to standard BeanFactory lifecycle capabilities, ApplicationContext implementations detect and invoke ApplicationContextAware beans as well as ResourceLoaderAware , ApplicationEventPublisherAware and MessageSourceAware beans.

除了标准的 BeanFactory 生命周期功能外,ApplicationContext 实现还检测并调用 ApplicationContextAware bean 以及 ResourceLoaderAware bean, ApplicationEventPublisherAware 和 MessageSourceAware bean。

1.2 ⭐️ConfigurableApplicationContext

与上一章的 ConfigurableBeanFactory 类似,它也给 ApplicationContext 提供了 “可写” 的功能,实现了该接口的实现类可以被客户端代码修改内部的某些配置。

1.2.1 ConfigurableApplicationContext提供了可配置的可能

SPI interface to be implemented by most if not all application contexts. Provides facilities to configure an application context in addition to the application context client methods in the ApplicationContext interface.

它是一个支持 SPI 的接口,它会被大多数(如果不是全部)应用程序上下文的落地实现。除了 ApplicationContext 接口中的应用程序上下文客户端方法外,还提供了用于配置应用程序上下文的功能。

这里又提到 SPI 了,咱回头讲到模块装配时再解释这个概念。后面它又提了,ConfigurableApplicationContext 给 ApplicationContext 添加了用于配置的功能,这个说法可以从接口方法中得以体现。ConfigurableApplicationContext 中扩展了 setParent 、setEnvironment 、addBeanFactoryPostProcessor 、addApplicationListener 等方法,都是可以改变 ApplicationContext 本身的方法。

1.2.2 ConfigurableApplicationContext只希望被调用启动和关闭

Configuration and lifecycle methods are encapsulated here to avoid making them obvious to ApplicationContext client code. The present methods should only be used by startup and shutdown code.

配置和与生命周期相关的方法都封装在这里,以避免暴露给 ApplicationContext 的调用者。本接口的方法仅应由启动和关闭代码使用。

ConfigurableApplicationContext 本身扩展了一些方法,但是它一般情况下不希望让咱开发者调用,而是只调用启动(refresh)和关闭(close)方法。注意这个一般情况是在程序运行期间的业务代码中,但如果是为了定制化 ApplicationContext 或者对其进行扩展,ConfigurableApplicationContext 的扩展则会成为切入的主目标。

1.3 EnvironmentCapable

capable 本意为“有能力的”,在这里解释为 “携带/组合” 更为合适。

在 SpringFramework 中,以 Capable 结尾的接口,通常意味着可以通过这个接口的某个特定的方法(通常是 **getXXX()** )拿到特定的组件。

按照这个概念说法,这个 EnvironmentCapable 接口中就应该通过一个 getEnvironment() 方法拿到 **Environment** ,事实上也确实如此:

public interface EnvironmentCapable {
	Environment getEnvironment();
}

1.3.1 ApplicationContext都具有EnvironmentCapable的功能

Interface indicating a component that contains and exposes an Environment reference.

All Spring application contexts are EnvironmentCapable, and the interface is used primarily for performing instanceof checks in framework methods that accept BeanFactory instances that may or may not actually be ApplicationContext instances in order to interact with the environment if indeed it is available.

它是具有获取并公开 Environment 引用的接口。

所有 Spring 的 ApplicationContext 都具有 EnvironmentCapable 功能,并且该接口主要用于在接受 BeanFactory 实例的框架方法中执行 instanceof 检查,以便可以与环境进行交互(如果实际上是 ApplicationContext 实例)。

从这部分可以知道,ApplicationContext 都实现了这个 EnvironmentCapable 接口,也就代表着所有的 ApplicationContext 的实现类都可以取到 Environment 抽象。至于 Environment 是什么,咱后面 IOC 高级部分会解释,这里简单解释一下。

Environment 是 SpringFramework 中抽象出来的类似于运行环境的独立抽象,它内部存放着应用程序运行的一些配置。

现阶段小伙伴可以这么理解:基于 SpringFramework 的工程,在运行时包含两部分:应用程序本身、应用程序的运行时环境。

1.3.2 ConfigurableApplicationContext可以获取ConfigurableEnvironment

As mentioned, ApplicationContext extends EnvironmentCapable, and thus exposes a getEnvironment() method; however, ConfigurableApplicationContext redefines getEnvironment() and narrows the signature to return a ConfigurableEnvironment. The effect is that an Environment object is 'read-only' until it is being accessed from a ConfigurableApplicationContext, at which point it too may be configured.

如上面所述,ApplicationContext 扩展了 EnvironmentCapable ,因此公开了 getEnvironment() 方法;但是,ConfigurableApplicationContext 重新定义了 getEnvironment() 并缩小了签名范围,以返回 ConfigurableEnvironment 。结果是环境对象是 “只读的” ,直到从 ConfigurableApplicationContext 访问它为止,此时也可以对其进行配置。

这里又看到 Configurable 的概念了,对于可配置的 ApplicationContext ,就可以获取到可配置的 Environment 抽象,这个也不难理解吧。

1.4 MessageSource

Strategy interface for resolving messages, with support for the parameterization and internationalization of such messages. Spring provides two out-of-the-box implementations for production:

  • org.springframework.context.support.ResourceBundleMessageSource: built on top of the standard java.util.ResourceBundle, sharing its limitations.

  • org.springframework.context.support.ReloadableResourceBundleMessageSource: highly configurable, in particular with respect to reloading message definitions.

用于解析消息的策略接口,并支持消息的参数化和国际化。SpringFramework 为生产提供了两种现有的实现:

  • ResourceBundleMessageSource:建立在标准 java.util.ResourceBundle 之上,共享其局限性。

  • ReloadableResourceBundleMessageSource:高度可配置,尤其是在重新加载消息定义方面。

1.5 ApplicationEventPublisher

类名可以理解为,它是事件的发布器。SpringFramework 内部支持很强大的事件监听机制,而 ApplicationContext 作为容器的最顶级,自然也要实现观察者模式中广播器的角色。文档注释中对于它的描述也是异常的简单:

Interface that encapsulates event publication functionality. Serves as a super-interface for ApplicationContext.

封装事件发布功能的接口,它作为 ApplicationContext 的父接口。

所以它就是一个很简单的事件发布/广播器而已,后续在 IOC 进阶部分学习事件驱动机制时会讲解它。

1.6 ResourcePatternResolver

这个接口可能是这几个扩展里最复杂的一个,从类名理解可以解释为“资源模式解析器”,实际上它是根据特定的路径去解析资源文件的。从下面的文档注释中,咱就可以深刻的体会 ResourcePatternResolver 的作用和扩展。

1.6.1 ResourcePatternResolver是ResourceLoader的扩展

Strategy interface for resolving a location pattern (for example, an Ant-style path pattern) into Resource objects. This is an extension to the ResourceLoader interface. A passed-in ResourceLoader (for example, an org.springframework.context.ApplicationContext passed in via org.springframework.context.ResourceLoaderAware when running in a context) can be checked whether it implements this extended interface too.

它是一个策略接口,用于将位置模式(例如,Ant 样式的路径模式)解析为 Resource 对象。 这是 ResourceLoader 接口的扩展。可以检查传入的 ResourceLoader(例如,在上下文中运行时通过 ResourceLoaderAware 传入的 ApplicationContext )是否也实现了此扩展接口。

可以发现,它本身还是 ResourceLoader 的扩展,ResourceLoader 实现最基本的解析,ResourcePatternResolver 可以支持 Ant 形式的带星号 ( * ) 的路径解析( Ant 形式会在下面看到)。

1.6.2 ResourcePatternResolver的实现方式有多种

PathMatchingResourcePatternResolver is a standalone implementation that is usable outside an ApplicationContext, also used by ResourceArrayPropertyEditor for populating Resource array bean properties.

PathMatchingResourcePatternResolver 是一个独立的实现,可在 ApplicationContext 外部使用,ResourceArrayPropertyEditor 使用它来填充 Resource 数组中 Bean 属性。

这一段列出了一种 ResourcePatternResolver 的独立实现:基于路径匹配的解析器,这种扩展实现的特点是会根据特殊的路径来返回多个匹配到的资源文件。

1.6.3 ResourcePatternResolver支持的Ant路径模式匹配

Can be used with any sort of location pattern (e.g. "/WEB-INF/*-context.xml"): Input patterns have to match the strategy implementation. This interface just specifies the conversion method rather than a specific pattern format.

可以与任何类型的位置模式一起使用(例如 "/WEB-INF/*-context.xml" ):输入模式必须与策略实现相匹配。该接口仅指定转换方法,而不是特定的模式格式。

根据前面的文档注释也知道,它支持的是 Ant 风格的匹配模式,这种模式可以有如下写法:

  • /WEB-INF/*.xml :匹配 /WEB-INF 目录下的任意 xml 文件

  • /WEB-INF/**/beans-*.xml :匹配 /WEB-INF 下面任意层级目录的 beans- 开头的 xml 文件

  • /**/*.xml :匹配任意 xml 文件

可以发现这种写法还是蛮灵活的,小伙伴们可以从网上搜索学习更多关于 Ant 风格的写法,不过常用的写法大概就上面几种,掌握写法即可。

1.6.4 ResourcePatternResolver可以匹配类路径下的文件

This interface also suggests a new resource prefix "classpath*:" for all matching resources from the class path. Note that the resource location is expected to be a path without placeholders in this case (e.g. "/beans.xml"); JAR files or classes directories can contain multiple files of the same name.

此接口还为类路径中的所有匹配资源建议一个新的资源前缀 "classpath*: "。请注意,在这种情况下,资源位置应该是没有占位符的路径(例如 "/beans.xml" ); jar 文件或类目录可以包含多个相同名称的文件。

文档注释中又提到了 ResourcePatternResolver 还可以匹配类路径下的资源文件,方式是在资源路径中加一个 classpath*: 的前缀。由此咱也可以知道,ResourcePatternResolver 不仅可以匹配 Web 工程中 webapps 的文件,也可以匹配 classpath 下的文件了。

2. ApplicationContext的实现类们

2.1 ⭐️AbstractApplicationContex

这个类是 ApplicationContext 最核心的实现类,没有之一。AbstractApplicationContext 中定义和实现了绝大部分应用上下文的特性和功能。

2.1.1 AbstractApplicationContext只构建功能抽象

Abstract implementation of the ApplicationContext interface. Doesn't mandate the type of storage used for configuration; simply implements common context functionality. Uses the Template Method design pattern, requiring concrete subclasses to implement abstract methods.

ApplicationContext 接口的抽象实现。不强制用于配置的存储类型;简单地实现通用上下文功能。使用模板方法模式,需要具体的子类来实现抽象方法。

AbstractApplicationContext 的抽象实现主要是规范功能(借助模板方法),实际的动作它不管,让子类自行去实现。

2.1.2 AbstractApplicationContext可以处理特殊类型的Bean

In contrast to a plain BeanFactory, an ApplicationContext is supposed to detect special beans defined in its internal bean factory: Therefore, this class automatically registers BeanFactoryPostProcessors, BeanPostProcessors, and ApplicationListeners which are defined as beans in the context.

与普通的 BeanFactory 相比,ApplicationContext 应该能够检测在其内部 Bean 工厂中定义的特殊 bean :因此,此类自动注册在上下文中定义为 bean 的 BeanFactoryPostProcessors ,BeanPostProcessors 和 ApplicationListeners 。

咱在第 6 章就知道,ApplicationContext 比 BeanFactory 强大的地方是支持更多的机制,这里面就包括了后置处理器、监听器等,而这些器,说白了也都是一个一个的 Bean ,BeanFactory 不会把它们区别对待,但是 ApplicationContext 就可以区分出来,并且赋予他们发挥特殊能力的机会。

2.1.3 AbstractApplicationContext可以转换为多种类型

A MessageSource may also be supplied as a bean in the context, with the name "messageSource"; otherwise, message resolution is delegated to the parent context. Furthermore, a multicaster for application events can be supplied as an "applicationEventMulticaster" bean of type ApplicationEventMulticaster in the context; otherwise, a default multicaster of type SimpleApplicationEventMulticaster will be used.

一个 MessageSource 也可以在上下文中作为一个普通的 bean 提供,名称为 "messageSource" 。否则,将消息解析委托给父上下文。此外,可以在上下文中将用于应用程序事件的广播器作为类型为 ApplicationEventMulticaster 的 "applicationEventMulticaster" bean 提供。否则,将使用类型为 SimpleApplicationEventMulticaster 的默认事件广播器。

咱上面看到了,ApplicationContext 实现了国际化的接口 MessageSource 、事件广播器的接口 ApplicationEventMulticaster ,那作为容器,它也会把自己看成一个 Bean ,以支持不同类型的组件注入需要。

2.1.4 AbstractApplicationContext提供默认的加载资源文件策略

Implements resource loading by extending DefaultResourceLoader. Consequently treats non-URL resource paths as class path resources (supporting full class path resource names that include the package path, e.g. "mypackage/myresource.dat"), unless the getResourceByPath method is overridden in a subclass.

通过扩展 DefaultResourceLoader 实现资源加载。因此,除非在子类中覆盖了 getResourceByPath() 方法,否则将非 URL 资源路径视为类路径资源(支持包含包路径的完整类路径资源名称,例如 "mypackage/myresource.dat" )。

默认情况下,AbstractApplicationContext 加载资源文件的策略是直接继承了 DefaultResourceLoader 的策略,从类路径下加载;但在 Web 项目中,可能策略就不一样了,它可以从 ServletContext 中加载(扩展的子类 ServletContextResourceLoader 等)。

看完了文档,小册在这个章节中多提一句:AbstractApplicationContext 中定义了一个特别特别重要的方法,它是控制 ApplicationContext 生命周期的核心方法:**refresh** 。下面是基本的方法定义,小伙伴们先对此有个印象即可,不需要深入进去看源码。对于源码的执行,小伙伴可以学完这些基础之后,参考《SpringBoot 源码解读与原理分析》的 11-15 章,学习 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,加载所有xml配置文件中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();
        }
    }
}

2.2 GenericApplicationContext

从注解驱动的 IOC 容器看起,GenericApplicationContext 已经是一个普通的类(非抽象类)了,它里面已经具备了 ApplicationContext 基本的所有能力了。

2.2.1 GenericApplicationContext组合了BeanFactory

Generic ApplicationContext implementation that holds a single internal DefaultListableBeanFactory instance and does not assume a specific bean definition format. Implements the BeanDefinitionRegistry interface in order to allow for applying any bean definition readers to it.

通用 ApplicationContext 的实现,该实现拥有一个内部 DefaultListableBeanFactory 实例,并且不采用特定的 bean 定义格式。另外它实现 BeanDefinitionRegistry 接口,以便允许将任何 bean 定义读取器应用于该容器中。

**GenericApplicationContext** 中组合了一个 **DefaultListableBeanFactory** !!!由此可以得到一个非常非常重要的信息:**ApplicationContext** 并不是继承了 **BeanFactory** 的容器,而是组合了 **BeanFactory** !

2.2.2 GenericApplicationContext借助BeanDefinitionRegistry处理特殊Bean

Typical usage is to register a variety of bean definitions via the BeanDefinitionRegistry interface and then call refresh() to initialize those beans with application context semantics (handling org.springframework.context.ApplicationContextAware, auto-detecting BeanFactoryPostProcessors, etc).

典型的用法是通过 BeanDefinitionRegistry 接口注册各种 Bean 的定义,然后调用 refresh() 以使用应用程序上下文语义来初始化这些 Bean(处理 ApplicationContextAware ,自动检测 BeanFactoryPostProcessors 等)。

这里又看到了 **BeanDefinitionRegistry** 了,上一章咱也提了一嘴它叫 Bean 定义的注册器,GenericApplicationContext 实现了它,可以自定义注册一些 Bean 。然而在 GenericApplicationContext 中,它实现的定义注册方法 registerBeanDefinition ,在底层还是调用的 DefaultListableBeanFactory 执行 registerBeanDefinition 方法,说明它也没有对此做什么扩展。

2.2.3 GenericApplicationContext只能刷新一次

In contrast to other ApplicationContext implementations that create a new internal BeanFactory instance for each refresh, the internal BeanFactory of this context is available right from the start, to be able to register bean definitions on it. refresh() may only be called once.

与为每次刷新创建一个新的内部 BeanFactory 实例的其他 ApplicationContext 实现相反,此上下文的内部 BeanFactory 从一开始就可用,以便能够在其上注册 Bean 定义。 refresh() 只能被调用一次。

这句话不是很好理解,小册换一种说法尝试着解释一下:由于 GenericApplicationContext 中组合了一个 DefaultListableBeanFactory ,而这个 BeanFactory 是在 GenericApplicationContext 的构造方法中就已经初始化好了,那么初始化好的 BeanFactory 就不允许在运行期间被重复刷新了。下面是源码中的实现:

public GenericApplicationContext() {
    // 内置的beanFactory在GenericApplicationContext创建时就已经初始化好了
    this.beanFactory = new DefaultListableBeanFactory();
}

protected final void refreshBeanFactory() throws IllegalStateException {
    if (!this.refreshed.compareAndSet(false, true)) {
        // 利用CAS,保证只能设置一次true,如果出现第二次,就抛出重复刷新异常
        throw new IllegalStateException(
                "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
    }
    this.beanFactory.setSerializationId(getId());
}

可如果是这样的话,它的文档注释为什么不直接说就可以呢,还非得加一句“与...相反”,那是因为有另外一类 ApplicationContext 它的设计不是这样的,咱下面会讲到,它就是 AbstractRefreshableApplicationContext 。

2.2.4 GenericApplicationContext的替代方案是用xml

For the typical case of XML bean definitions, simply use ClassPathXmlApplicationContext or FileSystemXmlApplicationContext, which are easier to set up - but less flexible, since you can just use standard resource locations for XML bean definitions, rather than mixing arbitrary bean definition formats. The equivalent in a web environment is org.springframework.web.context.support.XmlWebApplicationContext.

对于 XML Bean 定义的典型情况,只需使用 ClassPathXmlApplicationContext 或 FileSystemXmlApplicationContext ,因为它们更易于设置(但灵活性较差,因为只能将从标准的资源配置文件中读取 XML Bean 定义,而不能混合使用任意 Bean 定义的格式)。在 Web 环境中,替代方案是 XmlWebApplicationContext 。

这段注释它提到了 xml 的配置,之前也讲过,注解驱动的 IOC 容器可以导入 xml 配置文件,不过如果大多数都是 xml 配置的话,官方建议还是直接用 ClassPathXmlApplicationContext 或者 FileSystemXmlApplicationContext 就好。对比起灵活度来讲,咱也能清晰地认识到:注解驱动的方式在开发时很灵活,但如果需要修改配置时,可能需要重新编译配置类;xml 驱动的方式在修改配置时直接修改即可,不需要做任何额外的操作,但能配置的内容实在是有些有限。所以这也建议咱开发者在实际开发中,要权衡对比着使用。

2.2.5 GenericApplicationContext不支持特殊Bean定义的可刷新读取

For custom application context implementations that are supposed to read special bean definition formats in a refreshable manner, consider deriving from the AbstractRefreshableApplicationContext base class.

对于应该以可刷新方式读取特殊bean定义格式的自定义应用程序上下文实现,请考虑从 AbstractRefreshableApplicationContext 基类派生。

这个概念似乎很难理解,咱大可不必在意啦,它是解释怎么扩展自定义 ApplicationContext 实现的,咱目前也搞不了这些复杂的东西。

不过注意一点,它提到小册在上面刚刚提到的扩展实现 AbstractRefreshableApplicationContext 了,可见它的确很重要了,咱下面就来看它。

2.3 AbstractRefreshableApplicationContext

类名直译为 “可刷新的 ApplicationContext ”,它跟上面 GenericApplicationContext 的最大区别之一就是它可以被重复刷新。

2.3.1 AbstractRefreshableApplicationContext支持多次刷新

Base class for ApplicationContext implementations which are supposed to support multiple calls to refresh(), creating a new internal bean factory instance every time. Typically (but not necessarily), such a context will be driven by a set of config locations to load bean definitions from.

它是 ApplicationContext 接口实现的抽象父类,应该支持多次调用 refresh() 方法,每次都创建一个新的内部 BeanFactory 实例。通常(但不是必须)这样的上下文将由一组配置文件驱动,以从中加载 bean 的定义信息。

注释中明确说明了:每次都会创建一个新的内部的 **BeanFactory** 实例(也就是 DefaultListableBeanFactory ),而整个 ApplicationContext 的初始化中不创建。通过源码来看,它的内部也是组合 **DefaultListableBeanFactory** ,但构造方法中什么也没有干:

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
    @Nullable
    private DefaultListableBeanFactory beanFactory;

    public AbstractRefreshableApplicationContext() {
    }
}

那它是怎么创建 BeanFactory 的呢?借助 IDEA 观察方法列表,其中就有一个方法叫 creatBeanFactory :

protected DefaultListableBeanFactory createBeanFactory() {
    return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

2.3.2 AbstractRefreshableApplicationContext刷新的核心是加载Bean定义信息

The only method to be implemented by subclasses is loadBeanDefinitions, which gets invoked on each refresh. A concrete implementation is supposed to load bean definitions into the given DefaultListableBeanFactory, typically delegating to one or more specific bean definition readers. Note that there is a similar base class for WebApplicationContexts.

子类唯一需要实现的方法是 loadBeanDefinitions ,它在每次刷新时都会被调用。一个具体的实现应该将 bean 的定义信息加载到给定的 DefaultListableBeanFactory 中,通常委托给一个或多个特定的 bean 定义读取器。 注意,WebApplicationContexts 有一个类似的父类。

这段话告诉我们,既然是可刷新的 ApplicationContext ,那它里面存放的 Bean 定义信息应该是可以被覆盖加载的。由于 AbstractApplicationContext 就已经实现了 ConfigurableApplicationContext 接口,容器本身可以重复刷新,那么每次刷新时就应该重新加载 Bean 的定义信息,以及初始化 Bean 实例。

另外它还说,在 Web 环境下也有一个类似的父类,猜都能猜到肯定是名字里多了个 Web :AbstractRefreshableWebApplicationContext ,它的特征与 AbstractRefreshableApplicationContext 基本一致,不重复解释。

2.3.3 AbstractRefreshableWebApplicationContext额外扩展了Web环境的功能

org.springframework.web.context.support.AbstractRefreshableWebApplicationContext provides the same subclassing strategy, but additionally pre-implements all context functionality for web environments. There is also a pre-defined way to receive config locations for a web context.

AbstractRefreshableWebApplicationContext 提供了相同的子类化策略,但是还预先实现了 Web 环境的所有上下文功能。还有一种预定义的方式来接收 Web 上下文的配置位置。

与普通的 ApplicationContext 相比,WebApplicationContext 额外扩展的是与 Servlet 相关的部分( request 、ServletContext 等),AbstractRefreshableWebApplicationContext 内部就组合了一个 ServletContext ,并且支持给 Bean 注入 ServletContext 、ServletConfig 等 Servlet 中的组件。

2.3.4 几个重要的最终实现类

Concrete standalone subclasses of this base class, reading in a specific bean definition format, are ClassPathXmlApplicationContext and FileSystemXmlApplicationContext, which both derive from the common AbstractXmlApplicationContext base class; org.springframework.context.annotation.AnnotationConfigApplicationContext supports @Configuration-annotated classes as a source of bean definitions.

以特定的 bean 定义格式读取的该父类的具体独立子类是 ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext ,它们均从 AbstractXmlApplicationContext 基类扩展。 AnnotationConfigApplicationContext 支持 @Configuration 注解的类作为 BeanDefinition 的源。

最后一段它提了几个内置的最终实现类,分别是基于 xml 配置的 ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext ,以及基于注解启动的 AnnotationConfigApplicationContext 。这些咱已经有了解了,下面也会展开来讲。

2.4 AbstractRefreshableConfigApplicationContext

与上面的 AbstractRefreshableApplicationContext 相比较,只是多了一个 Config ,说明它有扩展跟配置相关的特性。翻看方法列表,可以看到有它自己定义的 getConfigLocations 方法,意为“获取配置源路径”,由此也就证明它确实有配置的意思了。

它的文档注释就一段话,解释的内容恰好就是上面刚刚说的:

AbstractRefreshableApplicationContext subclass that adds common handling of specified config locations. Serves as base class for XML-based application context implementations such as ClassPathXmlApplicationContext and FileSystemXmlApplicationContext, as well as org.springframework.web.context.support.XmlWebApplicationContext.

AbstractRefreshableApplicationContext 的子类,用于添加对指定配置位置的通用处理。作为基于 XML 的 ApplicationContext 实现(例如ClassPathXmlApplicationContext 、 FileSystemXmlApplicationContext 以及 XmlWebApplicationContext )的父类。

通篇就抽出来一句话:用于添加对指定配置位置的通用处理。由于它是基于 xml 配置的 ApplicationContext 的父类,所以肯定需要传入配置源路径,那这个配置的动作就封装在这个 AbstractRefreshableConfigApplicationContext 中了。

到这里,xml 终于浮出水面了,它就是最终 ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext 的直接父类了。

2.5 ⭐️AbstractXmlApplicationContext

2.5.1 AbstractXmlApplicationContext已具备基本全部功能

Convenient base class for ApplicationContext implementations, drawing configuration from XML documents containing bean definitions understood by an XmlBeanDefinitionReader. Subclasses just have to implement the getConfigResources and/or the getConfigLocations method. Furthermore, they might override the getResourceByPath hook to interpret relative paths in an environment-specific fashion, and/or getResourcePatternResolver for extended pattern resolution.

方便的 ApplicationContext 父类,从包含 XmlBeanDefinitionReader 解析的 BeanDefinition 的 XML 文档中提取配置。

子类只需要实现 getConfigResources 和/或 getConfigLocations 方法。此外,它们可能会覆盖 getResourceByPath 的钩子回调,以特定于环境的方式解析相对路径,和/或 getResourcePatternResolver 来扩展模式解析。

由于 AbstractXmlApplicationContext 已经接近于最终的 xml 驱动 IOC 容器的实现了,所以它应该有基本上所有的功能。又根据子类的两种不同的配置文件加载方式,说明加载配置文件的策略是不一样的,所以文档注释中有说子类只需要实现 getConfigLocations 这样的方法就好。

对于 AbstractXmlApplicationContext ,还有一个非常关键的部分需要咱知道,那就是加载到配置文件后如何处理。

2.5.2 AbstractXmlApplicationContext中有loadBeanDefinitions的实现

定位到源码中,可以在 AbstractXmlApplicationContext 中找到 loadBeanDefinitions 的实现:

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    // 借助XmlBeanDefinitionReader解析xml配置文件
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // Configure the bean definition reader with this context's
    // resource loading environment.
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    // Allow a subclass to provide custom initialization of the reader,
    // then proceed with actually loading the bean definitions.
    // 初始化BeanDefinitionReader,后加载BeanDefinition
    initBeanDefinitionReader(beanDefinitionReader);
    loadBeanDefinitions(beanDefinitionReader);
}

可以看到,它解析 xml 配置文件不是自己干活,是组合了一个 **XmlBeanDefinitionReader** ,让它去解析。而实际解析配置文件的动作,就很好理解了:

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        reader.loadBeanDefinitions(configResources);
    }
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        reader.loadBeanDefinitions(configLocations);
    }
}

可以看到就是调用上面文档注释中提到的 getConfigResources 和 getConfigLocations 方法,取到配置文件的路径 / 资源类,交给 BeanDefinitionReader 解析。

2.6 ClassPathXmlApplicationContext

终于到了一个咱非常熟悉的 ApplicationContext 了,咱已经很清楚它是从 classpath 下加载 xml 配置文件的 ApplicationContext 了,不过文档注释中也描述了一些内容和建议,咱还是要看一看的。

2.6.1 ClassPathXmlApplicationContext是一个最终落地实现

Standalone XML application context, taking the context definition files from the class path, interpreting plain paths as class path resource names that include the package path (e.g. "mypackage/myresource.txt"). Useful for test harnesses as well as for application contexts embedded within JARs.

独立的基于 XML 的 ApplicationContext ,它从 classpath 中获取配置文件,将纯路径解释为包含包路径的 classpath 资源名称(例如 mypackage / myresource.txt )。对于测试工具以及 jar 包中嵌入的 ApplicationContext 很有用。

这段话写的很明白,它支持的配置文件加载位置都是 classpath 下取,这种方式的一个好处是:如果工程中依赖了一些其他的 jar 包,而工程启动时需要同时传入这些 jar 包中的配置文件,那 ClassPathXmlApplicationContext 就可以加载它们。

2.6.2 ClassPathXmlApplicationContext使用Ant模式声明配置文件路径

The config location defaults can be overridden via getConfigLocations, Config locations can either denote concrete files like "/myfiles/context.xml" or Ant-style patterns like "/myfiles/*-context.xml" (see the org.springframework.util.AntPathMatcher javadoc for pattern details).

可以通过 getConfigLocations 方法覆盖配置文件位置的默认值,配置位置可以表示具体的文件,例如 /myfiles/context.xml ,也可以表示Ant样式的模式,例如 /myfiles/*-context.xml(请参见 AntPathMatcher 的 javadoc 以获取模式详细信息)。

上面 AbstractXmlApplicationContext 中就说了,可以重写 getConfigLocations 方法来调整配置文件的默认读取位置,它这里又重复了一遍。除此之外它还提到了,加载配置文件的方式可以使用 Ant 模式匹配(比较经典的写法当属 web.xml 中声明的 application-*.xml )。

2.6.3 ClassPathXmlApplicationContext解析的配置文件有先后之分

Note: In case of multiple config locations, later bean definitions will override ones defined in earlier loaded files. This can be leveraged to deliberately override certain bean definitions via an extra XML file.

注意:如果有多个配置位置,则较新的 BeanDefinition 会覆盖较早加载的文件中的 BeanDefinition ,可以利用它来通过一个额外的 XML 文件有意覆盖某些 BeanDefinition 。

这一点是配合第一点的多配置文件读取来的。通常情况下,如果在一个 jar 包的 xml 配置文件中声明了一个 Bean ,并且又在工程的 resources 目录下又声明了同样的 Bean ,则 jar 包中声明的 Bean 会被覆盖,这也就是配置文件加载优先级的设定。

2.6.4 ApplicationContext可组合灵活使用

This is a simple, one-stop shop convenience ApplicationContext. Consider using the GenericApplicationContext class in combination with an org.springframework.beans.factory.xml.XmlBeanDefinitionReader for more flexible context setup.

这是一个简单的一站式便利 ApplicationContext 。可以考虑将 GenericApplicationContext 类与 XmlBeanDefinitionReader 结合使用,以实现更灵活的上下文配置。

最后文档中并没有非常强调 ClassPathXmlApplicationContext 的作用,而是提了另外一个建议:由于 ClassPathXmlApplicationContext 继承了 AbstractXmlApplicationContext ,而 AbstractXmlApplicationContext 实际上是内部组合了一个 XmlBeanDefinitionReader ,所以就可以有一种组合的使用方式:利用 GenericApplicationContext 或者子类 AnnotationConfigApplicationContext ,配合 XmlBeanDefinitionReader ,就可以做到注解驱动和 xml 通吃了。

2.7 AnnotationConfigApplicationContext

最后一个,咱介绍一个也用过很多次的了,就是注解驱动的 IOC 容器。它本身继承了 GenericApplicationContext ,那自然它也只能刷新一次。同样是最终的落地实现,它自然也应该跟 ClassPathXmlApplicationContext 类似的有一些特征,下面咱来看看。

2.7.1 AnnotationConfigApplicationContext是一个最终落地实现

独立的注解驱动的 ApplicationContext ,接受组件类作为输入,特别是使用 @Configuration 注解的类,还可以使用普通的 @Component 类型和符合 JSR-330 规范(使用 javax.inject 包的注解)的类。

注解驱动,除了 @Component 及其衍生出来的几个注解,更重要的是 @Configuration 注解,一个被 @Configuration 标注的类相当于一个 xml 文件。至于下面还提到的关于 JSR-330 的东西,它没有类似于 @Component 的东西(它只是定义了依赖注入的标准,与组件注册无关),它只是说如果一个组件 Bean 里面有 JSR-330 的注解,那它能给解析而已。

2.7.2 AnnotationConfigApplicationContext解析的配置类也有先后之分

允许使用 register(Class ...) 一对一注册类,以及使用 scan(String ...) 进行类路径的包扫描。 如果有多个 @Configuration 类,则在以后的类中定义的 @Bean 方法将覆盖在先前的类中定义的方法。这可以通过一个额外的 @Configuration 类来故意覆盖某些 BeanDefinition 。

这个操作就跟上面 ClassPathXmlApplicationContext 如出一辙了,它也有配置覆盖的概念。除此之外,它上面还说了初始化的两种方式:要么注册配置类,要么直接进行包扫描。由于注解驱动开发中可能没有一个主配置类,都是一上来就一堆 @Component ,这个时候完全可以直接声明根扫描包,进行组件扫描。

有关 FileSystemXmlApplicationContext ,以及 Web 环境下扩展的 ApplicationContext ,本章不作更多的解析,小伙伴们可以举一反三,根据现有已经了解的知识,对比学习其它的一些 IOC 容器的实现。

img

Standalone application context, accepting component classes as input — in particular @Configuration-annotated classes, but also plain types and JSR-330 compliant classes using javax.inject annotations.

Allows for registering classes one by one using register(Class...) as well as for classpath scanning using scan(String...). In case of multiple classes, methods defined in later classes will override those defined in earlier classes. This can be leveraged to deliberately override certain bean definitions via an extra class.

@Component
@Configuration
@Bean
@Configuration