ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Spring系列02:BeanFactory 与 ApplicationContext

Spring系列02:BeanFactory 与 ApplicationContext

这题你大概率只答了一半

面试八成会被问:「BeanFactory 和 ApplicationContext 有什么区别?」

多数人的回答停在「ApplicationContext 更高级、功能更多」,再往下问「多在哪」「为什么 Boot 默认用它」「两者启动行为有啥不同」,就开始含糊。这道题的坑,不在记不住,而在只背了结论没看透关系。今天把它答全。

一句话定位

BeanFactory是 Spring IoC 容器的最底层接口,只负责「管理 bean」这一件事——bean 的定义、实例化、装配、生命周期,它全包了。

ApplicationContext是它的超集:直接extends BeanFactory,在容器能力之上,又叠了一整套面向应用框架的企业级能力。(关系出处:官方文档 · Container Overview / Additional Capabilities of the ApplicationContext)

一句话类比:BeanFactory 是「发动机」,ApplicationContext 是「整车」。发动机能跑,但整车才给了你方向盘、空调和音响——而 Spring Boot 出厂装的就是整车。

继承关系

ApplicationContext直接继承BeanFactory,还横向扩展了MessageSource、ApplicationEventPublisher、ResourceLoader,并通过HierarchicalBeanFactory支持层次化上下文。层级可以这么看:

  • BeanFactory(根接口,纯容器)
    • HierarchicalBeanFactory(支持父子容器)
      • ApplicationContext(同时实现以下三个接口)
        • MessageSource— 国际化
        • ApplicationEventPublisher— 事件发布
        • ResourceLoader— 资源加载
        • EnvironmentCapable— 环境与 Profile(属 Environment 抽象章节)
      • 常用实现:ClassPathXmlApplicationContext、AnnotationConfigApplicationContext、WebApplicationContext(Web 层)

ApplicationContext 多出的四大能力(重点)

官方「Additional Capabilities」一节明确列出了 BeanFactory 没有、ApplicationContext 原生具备的四项能力:

  • MessageSource(国际化):ApplicationContext 继承了MessageSource,天生支持 i18n。启动时它会自动在容器里查找名为messageSource的 bean,找不到再找父容器,都没有则用空的DelegatingMessageSource兜底。也就是说,拿到ApplicationContext就能直接取多语言文案。(出处:官方 · Additional Capabilities of the ApplicationContext)
  • ApplicationEventPublisher(事件机制):通过ApplicationEventPublisher发布事件,由实现了ApplicationListener的 bean 接收——标准观察者模式。Spring 4.2 起还支持@EventListener注解模型,能直接发布任意对象(自动包装成事件)。内置ContextRefreshedEvent、ContextClosedEvent等标准事件。(出处同上)
  • ResourceLoader(统一资源访问):ApplicationContext 本身就是ResourceLoader,能用统一方式加载 classpath、文件系统、URL 等各种位置的资源,不用再自己拼路径。需要资源的 bean 还能通过ResourceLoaderAware回调拿到它。(出处同上)
  • HierarchicalBeanFactory(层次化上下文):可以加载多个层次化的上下文,让每一层专注某一层(比如 Web 层独立一个上下文)。父子容器之间 bean 可见性有规则,这是 Spring MVC 父子容器模型的基础。(出处同上)

诚实提醒:网上常把EnvironmentCapable(Environment / Profile 支持)也单列成「第五大能力」。ApplicationContext 确实实现了它,但它属于官方的 Environment 抽象章节,不在「Additional Capabilities」这一节的标准清单里。写进文章时别张冠李戴。

一个常被忽略的关键差异:单例预实例化

光看接口还不够,两者默认的实例化时机才是实战分水岭:

  • BeanFactory默认懒加载:第一次getBean()才去实例化。
  • ApplicationContext默认启动时就预实例化所有单例(除非显式标lazy-init)。

这个差异直接决定了体验:ApplicationContext 启动稍慢、占点内存,但启动期就能把配置错误(比如循环依赖、缺 Bean)一次性暴露;BeanFactory 启动飞快,可隐患会一直藏到你第一次真正用到那个 bean 的请求上才爆雷。(关于 BeanFactory 的默认行为,出处:官方文档 · The BeanFactory API)

十行代码亲眼验证

两种容器并排放一起,差异立刻具象化:

publicclassContainerStartupDemo{staticclassHeavyBean{HeavyBean(){System.out.println("HeavyBean 被实例化了!");}}@ConfigurationstaticclassConfig{@BeanHeavyBeanheavyBean(){returnnewHeavyBean();}}publicstaticvoidmain(String[]args){// ApplicationContext:构造器一跑完,HeavyBean 已经创建varctx=newAnnotationConfigApplicationContext(Config.class);// 输出:HeavyBean 被实例化了! ← 启动期就发生// BeanFactory:直到 getBean 才创建varfactory=newDefaultListableBeanFactory();newAnnotatedBeanDefinitionReader(factory).register(Config.class);System.out.println("注册完,但 HeavyBean 还没创建");factory.getBean("heavyBean");// 此刻才打印实例化日志}}

这个「启动期全量实例化」正是「fail-fast」的来源:某个 bean 的依赖缺失、循环引用、@Value占位符解析不到,全在你部署那一刻报出来,而不是上线三天后某个用户触发请求时 500。生产上这就是「部署失败」和「线上事故」的差别。

Boot 时代还留了个开关:spring.main.lazy-initialization=true可以全局改成懒加载(冷启动更快、按需实例化),代价是把 fail-fast 也关掉了——接口首跳延迟变大、隐患延后暴露。灰度发布用它换启动速度可以,常态化要掂量。

追问链:再往下会被问什么

  1. 「@Autowired 拿到的到底是 BeanFactory 还是 ApplicationContext?」——都能注入:字段类型声明为BeanFactory拿到的是容器自身(ApplicationContext 实现了它);日常建议注入ApplicationContext,四大能力才可用。
  2. 「父子容器到底怎么查找 bean?」——子容器getBean找不到会沿父链向上查,反之父容器看不到子容器的 bean。这解释了为什么老式 Spring MVC(父子容器双 XML 时代)里 Controller 能注入 Service、Service 却注入不了 Controller。Boot 单容器把这道题简化了,但 Spring Cloud 等场景仍会造子容器,规则要懂。
  3. 「DefaultListableBeanFactory 是什么角色?」——它是ConfigurableListableBeanFactory的终端实现、注册表 + 生产线合一的那个类:AnnotationConfigApplicationContext内部就是包着它工作。看容器源码,90% 从这个类入口。

到底怎么选

  • 99% 的场景、尤其是 Spring Boot 应用:直接用ApplicationContext,底层就是它(如AnnotationConfigServletWebServerApplicationContext)。那四个能力和启动期校验,都是白送的。
  • BeanFactory 仅适合:资源极度受限、需要极致轻量的嵌入场景,或者你只想以纯编程方式手动控制 bean 的创建节奏。

一句话收束:ApplicationContext = BeanFactory + 四大企业级能力 + 启动期预实例化单例。前者是「能用」,后者才是「好用且省心」。


📌 版本与出处说明:本文基于Spring Framework 7.x 官方 Reference(查阅时文档版本 7.0.10,2026-10)撰写,核心概念均对照官方文档提炼,正文关键处标注了对应官方小节。官方文档若改版,以官网最新版为准。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进