Spring框架之ApplicationContext源码学习

介绍

Spring‑Framework 核心上下文顶级接口,属于 Spring IOC 容器的门面接口 (Facade)。

接口总览

java 复制代码
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver

EnvironmentCapable

获取环境配置对象Environment,读取配置文件、系统属性、环境变量。

外部配置抽象,容器与配置解耦,支持 profile、属性占位符。

ListableBeanFactory

可枚举 Bean 的 BeanFactory,可以获取全部 bean 名称、按类型获取 bean 列表。

批量 bean 查询能力 ,基础BeanFactory只能按名称单个获取。

HierarchicalBeanFactory

分层 BeanFactory,支持父子容器层级。

容器层级架构,SpringMVC 就是典型:父容器 Spring 根容器,子容器 MVC 容器,父子隔离 Bean

MessageSource

国际化消息解析。

i18n 能力,把国际化能力内置到容器,业务直接从上下文拿消息,不用自己维护资源文件。

ApplicationEventPublisher

事件发布器,发布 Spring 事件。

容器内置事件驱动,观察者模式,解耦启动、刷新、关闭等生命周期业务逻辑。

ResourcePatternResolver

资源加载解析,支持 classpath*:、file: 等通配符加载资源。

统一资源抽象,屏蔽磁盘、classpath、网络资源差异。

🔔架构核心设计思想:接口多继承,能力组合

原始BeanFactory只是最底层 IOC 容器,只提供 Bean 实例获取。

ApplicationContext不修改原有 BeanFactory 接口,通过多继承把「配置、层级、国际化、事件、资源」多种能力组合叠加,变成一个功能完备的高级 IOC 容器门面。
👉门面模式 (Facade) :对外暴露ApplicationContext作为统一入口,内部实际委托给内部持有的DefaultListableBeanFactory完成真正 Bean 管理,外部应用几乎不会直接操作底层 BeanFactory。
注意:ApplicationContext只是接口,不做任何实现 ;真正实现类:AbstractApplicationContext抽象模板实现,再往下ClassPathXmlApplicationContext、AnnotationConfigApplicationContext。

源码解析

java 复制代码
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
	/**
	 * 获取当前上下文实例的唯一标识ID
	 * @return 上下文唯一id,允许返回null
	 *
	 * 架构用途:
	 * 1. 同一个JVM可以存在多个ApplicationContext实例(父子容器、多模块),用id区分;
	 * 2. 日志输出、监控埋点、多容器隔离识别;
	 * 3. 可由用户自定义设置,ConfigurableApplicationContext#setId()
	 */
	String getId();

	/**
	 * 获取该上下文所属部署应用的应用名称
	 * @return 部署应用名称,默认返回空字符串
	 *
	 * 架构用途:
	 * 用于多应用部署场景,区分归属哪个应用;
	 * 一般SpringBoot会填充为spring.application.name,普通Spring项目默认为""
	 */
	String getApplicationName();

	/**
	 * 获取上下文友好展示名称
	 * @return 用于打印日志的展示名称,绝对不为null
	 *
	 * 架构用途:
	 * 纯粹日志、调试输出,便于排查多容器问题;
	 * 例如输出:AnnotationConfigApplicationContext@2d209079
	 */
	String getDisplayName();

	/**
	 * 获取上下文第一次加载完成的时间戳(毫秒)
	 * @return 容器初始化完成的毫秒时间戳
	 *
	 * 架构用途:
	 * 1. 统计容器启动耗时;
	 * 2. 判断容器什么时候完成refresh刷新;
	 * ⚠️注意:不是对象new的时间,是refresh()执行完成的时间点
	 */
	long getStartupDate();

	/**
	 * 获取父上下文对象
	 * @return 返回父ApplicationContext,如果是根容器没有父容器则返回null
	 *
	 * 【父子容器核心】
	 * 1. 典型场景SpringMVC:Root WebApplicationContext(父) 、Servlet WebApplicationContext(子)
	 * 2. Bean查找规则:子容器找不到bean,会向上委托父容器查找;父容器看不到子容器Bean
	 * 3. 可以用来做模块隔离,公共Bean放父容器,模块私有Bean放子容器
	 */
	ApplicationContext getParent();

	/**
	 * 暴露AutowireCapableBeanFactory能力
	 * @return 返回具备自动装配能力的BeanFactory
	 * @throws IllegalStateException 如果容器还没有refresh刷新,或者不支持该工厂抛出异常
	 *
	 * 🔴非常重要的方法,业务代码极少用,但是框架拓展高频!
	 *
	 * 背景:普通ApplicationContext门面,没有暴露「手动执行bean生命周期、依赖注入」的API。
	 * AutowireCapableBeanFactory能干什么:
	 * 1. 对new出来的外部对象(不在Spring容器管理的对象)执行依赖注入 @Autowired;
	 * 2. 手动执行bean的初始化方法、Aware回调、AOP代理创建;
	 *
	 * 使用场景举例:
	 * 1. Spring集成Quartz,quartz自己new Job对象,需要spring注入依赖;
	 * 2. 手动new领域对象,想要享受Spring自动装配;
	 *
	 * 重要提醒:
	 * 调用该方法前提:容器必须已经执行完refresh(),否则抛异常;
	 * ConfigurableApplicationContext#getBeanFactory()也可以拿到底层工厂,本方法是便捷封装。
	 */
	AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

架构层面深度拆解

BeanFactory vs ApplicationContext

  • BeanFactory:底层 IOC 容器,最小核心集合,只做 Bean 实例化获取,惰性初始化 bean。
  • ApplicationContext:继承BeanFactory子接口,高级容器门面,默认立刻初始化所有单例 Bean,叠加配置、事件、国际化、资源、父子容器全套能力。

设计取舍:Spring 没有把所有方法塞到 BeanFactory,使用接口拆分,单一职责。底层 API 轻量,上层门面功能丰富。

2. 父子容器 Hierarchical 层级设计

getParent()体现容器层级架构:

  • 子容器可以看到父容器 Bean,父看不到子容器;
  • 适合拆分:公共组件、dao 层放在父容器;controller、web 相关放在子容器;
  • SpringBoot 现在很少手动构建父子容器,但底层代码完整保留这套能力。

3. getAutowireCapableBeanFactory()的设计思考

为什么不直接把这个 API 放普通 BeanFactory?

AutowireCapableBeanFactory包含大量 bean 生命周期内部操作,属于框架内部 API,不希望普通业务开发随意调用 ,所以没有暴露在普通BeanFactory。

只有通过ApplicationContext主动获取,提示使用者:这是高级能力,谨慎使用。

4. 门面模式的实现细节

ApplicationContext接口本身不会实现 Bean 逻辑。

以AbstractApplicationContext举例:

内部持有一个真正的DefaultListableBeanFactory实例;ApplicationContext 所有继承来的 BeanFactory 接口方法,全部委托给内部这个 beanFactory 对象完成。

ApplicationContext = 装饰门面,真正干活的 BeanFactory 在内部持有。

5. 接口能力拆分的好处

  1. 最小依赖:如果你只需要资源加载,你可以只依赖ResourcePatternResolver接口,不需要整个上下文;
  2. 可替换实现:可以自定义实现 ApplicationContext 接口,替换容器实现;
  3. 接口职责单一,每个接口只负责一块能力,符合接口隔离原则 ISP。
相关推荐
且撷相思红豆枝2 小时前
Simulink学习笔记(一)
笔记·学习·matlab
程序员清风2 小时前
缓存、索引与数据结构的工程选择
数据结构·spring·缓存
白露与泡影2 小时前
Spring AI Alibaba -- 文生图、文生音及向量化
java·人工智能·spring
滕州市燕猫虎计算机科技工作室个体工商户2 小时前
Java,Java NIO,Java NIO2,Java AIO,AsynchronousServerSocketChannel
java·开发语言·nio·aio·nio2
学长毕设3 小时前
基于springboot的社会志愿者管理系统-附源码
java·spring boot·后端
木头科技3 小时前
【AI 工程化第十六篇】Spring AI 多模态 RAG 实战:图片、扫描件、表格与图文证据链
java·人工智能·spring
驭渊的小故事3 小时前
从 JVM 底层看泛型:泛型擦除、Signature 属性与 Super Type Token 模式
java·开发语言·jvm
菜鸟小杰子3 小时前
手动修改 Spring Boot 嵌套 JAR 包:大包小包隔离打包实战
java·jar
计算机编程-吉哥3 小时前
计算机毕业设计 基于 SpringBoot + Vue 的剧本杀系统 Java毕业设计【任务书、开题报告、中期报告、论文、源码】
java·vue.js·spring boot·毕业设计·课程设计·计算机毕业设计选题