1. 从一个例子🌰开始
小陈申请加盟咖啡店后,小陈收到总部寄来的《开店规格单》。这份文件允许每家分店填写自己的店铺配置标准:
-
分店名称:小陈咖啡店
-
咖啡机:默认咖啡机
-
咖啡豆供应商:默认咖啡豆供应商
小陈发现,只要填写好这张表格寄回总部,剩下的工作完全不用操心,总部的供应链与设备管理中心会为他装配好一切,处理好一切依赖

2. 元数据与容器概念引入
上面的例子帮助我们理解spring ioc功能中的三个重要角色
-
开店规格单(对应Spring的BeanDefinition)
就像表格中每一行配置定义了咖啡店的"基因"(用什么机器、找哪家供应商),BeanDefinition是Spring中描述对象的"元数据"。它不关心咖啡机如何运输,只记录"这个对象该长什么样"(类名、属性值、依赖关系等)。
-
供应链与设备管理中心(对应Spring的BeanFactory)
当总部的供应链与设备管理中心收到开店规格单后,设备管理中心会按表格内容组装咖啡机、安排供应商。这就像BeanFactory的核心能力------读取BeanDefinition配置,通过反射创建对象,并进行依赖注入。
-
总部(对应Spring的ApplicationContext)
总部除了有供应链与设备管理中心之外,还有营销部门和其他部门,其中营销部门负责开展活动,并且通知到其他分店。也就说说总部不仅仅有供应链与设备管理中心的能力(按照规格单来组装咖啡店)还有开展活动通知其他分店或者顾客的能力
对应到ApplicationContext,它不仅继承BeanFactory的对象创建和依赖注入,还有事件发布订阅的能力。
发布订阅:spring提供的事件能力,利用发布订阅模型解耦事件发布方和事件订阅方,后续章节详细讲述
3.结合代码理解元数据与容器是如何协作的

3.1 描述咖啡店的依赖 & Java类如何描述依赖
在上述故事中,是小陈填写了《开店规格单》写明了自己依赖咖啡机,咖啡供应商户。这对应编码中,我们使用@Autowired 注解来描述依赖
Java
@Component
public class CoffeeShop {
// 表明我们需要咖啡供应
@Autowired
private CoffeeBeansSupplier coffeeBeansSupplier;
// 表明我们需要咖啡机器
@Autowired
private CoffeeMachine coffeeMachine;
public void saleCoffee() {
coffeeBeansSupplier.supply();
coffeeMachine.product();
System.out.println("saleCoffee");
}
}
3.2 填写《开店规格单》& 生成BeanDefinition
生成BeanDefinition的过程在Spring中进行了隐藏,我们平时写业务逻辑并不会关注到BeanDefinition是如何生成的,当然Spring也提供了一些API来使用:
Java
// 小陈填写:开店规格单
BeanDefinition coffeeShopDefinition =new AnnotatedGenericBeanDefinition(CoffeeShop.class);
如上就是使用AnnotatedGenericBeanDefinition的构造方法传入CoffeeShop这个类,自动生成BeanDefinition,其内部会反射解析注解,解析到@Autowired的时候,就知道CoffeeShop依赖咖啡豆供应商,咖啡机
3.3 供应链与设备管理中心装配好一切&用BeanFactory生成CoffeeShop对象
3.3.1 初始化供应链与设备管理中心
java
// 供应链与设备管理中心
private static DefaultListableBeanFactory equipmentManagementCenter;
static {
initEquipmentManagementCenter();
}
// 初始化设备管理中心
private static void initEquipmentManagementCenter() {
// 设备管理中心
equipmentManagementCenter = new DefaultListableBeanFactory();
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
processor.setBeanFactory(equipmentManagementCenter);
equipmentManagementCenter.addBeanPostProcessor(processor);
// 默认的咖啡豆供应商
BeanDefinition defaultCoffeeBeansSupplierDefinition = new AnnotatedGenericBeanDefinition(DefaultCoffeeBeansSupplier.class);
// 默认的咖啡豆机器
BeanDefinition defaultCoffeeMachineDefinition = new AnnotatedGenericBeanDefinition(DefaultCoffeeMachine.class);
// 供应链设备管理中心,记录了【默认的咖啡豆供应商】和【默认的咖啡豆机器】
equipmentManagementCenter.registerBeanDefinition("coffeeBeansSupplier", defaultCoffeeBeansSupplierDefinition);
equipmentManagementCenter.registerBeanDefinition("coffeeMachine", defaultCoffeeMachineDefinition);
}
重点关注红色部分的逻辑:这里表示向供应链与设备管理中心(BeanFactory)注册默认的咖啡店供应商(coffeeBeansSupplier)和默认的咖啡机(coffeeMachine)
可以想象成供应链与设备管理中心这个部门刚成立的时候建立的人脉(咖啡豆供应商)和购入的咖啡机,毕竟巧妇难为无米之炊,如果供应链与设备管理中心都没有咖啡机,那么更不可能为小陈的咖啡店提供咖啡机。
3.3.2 生成CoffeeShop
java
public static void main(String[] args) {
// 小陈填写:开店规格单
BeanDefinition coffeeShopDefinition = new AnnotatedGenericBeanDefinition(CoffeeShop.class);
// 小陈把开店规格单寄回总部
equipmentManagementCenter.registerBeanDefinition("小陈咖啡店", coffeeShopDefinition);
// 总部处理依赖安排机器和咖啡豆供应商
CoffeeShop coffeeShop = (CoffeeShop) equipmentManagementCenter.getBean("小陈咖啡店");
// 小陈直接开业
coffeeShop.saleCoffee();
}
如上,我们向供应链与设备管理中心提交小陈咖啡店的《开店规格单》,然后调用getBean方法,就能拿到小陈咖啡店类,直接调用saleCoffee就可以进行营业啦!
4.总部的秘密------ApplicationContext和其设计哲学
4.1 ApplicationContext和BeanFactory是什么关系

如上图可以看到,总部和设备管理中心的关系是,设备管理中心是总部的一部门,设备管理中心属于总部,总部具备设备管理中心的一切能力
同理ApplicationContext和BeanFactory的关系是,ApplicationContext包含BeanFactory,ApplicationContext具备BeanFactory的一切能力
这里有点绝对,从接口维度来说是这样的,但是具体实现可以不必这样
以ApplicationContext的实现类GenericApplicationContext来举例,GenericApplicationContext具备一个beanFactory字段
任何关于BeanFactory这个接口的功能,其实都是转交给beanFactory字段来进行
这里其实体现了组合大于继承的思想
4.2 组合大于继承
1 什么是继承,什么是组合
-
继承表示 "is-a" 关系,即子类是一种父类。子类通过继承父类,自动获得父类的属性和方法,并可以扩展或覆盖这些行为
-
组合表示 "has-a" 关系,即一个类通过持有其他类的实例作为成员变量,委托调用其方法来实现功能复用。
2 从ApplicationContext和BeanFactory看待继承和组合
接口是能力象征:GenericApplicationContext实现了ApplicationContext,那么说明GenericApplicationContext有所有ApplicationContext的能力------发布事件(营销中心)和管理对象的依赖(设备中心)
接口用于定义 "对象应该具备的能力",而不关心具体的实现细节。它类似于现实世界中的 "标准" 或 "契约",规定了一组方法(行为),任何实现该接口的类必须遵守这些方法定义。
ApplicationContext接口上实现了BeanFactory,因此我们可以说ApplicationContext "is-a" BeanFactory
GenericApplicationContext内部组合一个BeanFactory的实现------DefaultListableBeanFactory,所有BeanFactory的相关操作比如getBean都交给内部组合的DefaultListableBeanFactory进行
- 内部 BeanFactory 可独立变化:GenericApplicationContext 的 BeanFactory 相关功能完全由内部的 DefaultListableBeanFactory 实现,ApplicationContext 自身可以专注于扩展高级功能(如事件发布、资源加载等),职责分离清晰。
总部把组装咖啡机这种事情都交给设备管理中心,从而关注自身,可以进军其他行业
- 避免继承的脆弱性:如果通过继承 DefaultListableBeanFactory 实现,父类的任何修改都可能影响子类;而组合仅依赖接口,内部实现可随时替换(例如替换为自定义 BeanFactory)。
-
如果总部继承设备管理中心,等于把设备管理中心建在总部的写字楼里面,设备管理中心起火将营销总部
-
铁打的总部,流水的设备管理中心,总部对设备管理中心可以随时换
- 独立扩展维度:ApplicationContext 需要同时实现多个功能维度(如 BeanFactory、ApplicationEventPublisher)。如果通过继承多个父类实现,会导致复杂的类层次;而通过组合,每个功能模块可以独立实现后注入
总部还有营销部门,Java时单继承的,无法同时实现多个类,哪怕可以也会导致层级太多,不例如扁平管理
5. 面试题&总结
这里的答案更贴合本期视频,并非是完美答案,随着你对Spring的理解更深,你的回答将有更多自己的理解,以及更全面
5.1 什么是BeanFactory,什么是ApplicationContext
- BeanFactory是Spring的基础容器,负责Bean的实例化、配置及生命周期管理。提供基础的IoC功能,如getBean()方法获取Bean。管理Bean的依赖注入和基础生命周期(如init和destroy方法)(下期内容)。
就如同瑞幸的设备管理中心,为每一个咖啡店安排咖啡机(IoC),帮助每一个加盟者开咖啡店(getBean),在每一个分店关店的时候还会进行咖啡机的回收(基础生命周期,下期内容)
- ApplicationContext是BeanFactory的子接口,提供企业级功能,是Spring的高级容器。除了BeanFactory具备的功能外还有例如事件发布的能力(下下下下期内容)、国际化支持、资源访问(统一加载文件、URL等资源)(后续内容会提到)
就如同瑞幸的总部,除了有设备管理中心的能力外(ioc)还有营销部门,可以将每一次的活动消息推送到各个关心的用户(事件发布能力),还提供海外国际化的支持。
5.2 BeanFactory 和 ApplicationContext 的核心区别是什么?
-
BeanFactory:基础容器,提供 Bean 的注册、配置和生命周期管理,支持延迟加载(Lazy Loading)。
-
ApplicationContext:扩展自 BeanFactory,提供企业级功能(如国际化、事件发布、资源加载)。
5.3 ApplicationContext 是如何实现 BeanFactory 功能的?
ApplicationContext 接口继承 BeanFactory,但其实现类(如 GenericApplicationContext)通过组合内部的 BeanFactory 实例(如 DefaultListableBeanFactory)委托实现核心方法(如 getBean()),而非直接继承 BeanFactory 的实现类,体现了组合优于继承的设计原则
这里可以主动提起,这是一个优秀的设计,体现了组合大于继承的原则,然后接着说组合为何优于继承
- 内部 BeanFactory 可独立变化:GenericApplicationContext 的 BeanFactory 相关功能完全由内部的 DefaultListableBeanFactory 实现,ApplicationContext 自身可以专注于扩展高级功能(如事件发布、资源加载等),职责分离清晰。
总部把组装咖啡机这种事情都交给设备管理中心,从而关注自身,可以进军其他行业
- 避免继承的脆弱性:如果通过继承 DefaultListableBeanFactory 实现,父类的任何修改都可能影响子类;而组合仅依赖接口,内部实现可随时替换(例如替换为自定义 BeanFactory)。
-
如果总部继承设备管理中心,等于把设备管理中心建在总部的写字楼里面,设备管理中心起火将营销总部
-
铁打的总部,流水的设备管理中心,总部对设备管理中心可以随时换
- 独立扩展维度:ApplicationContext 需要同时实现多个功能维度(如 BeanFactory、ApplicationEventPublisher)。如果通过继承多个父类实现,会导致复杂的类层次;而通过组合,每个功能模块可以独立实现后注入
总部还有营销部门,Java时单继承的,无法同时实现多个类,哪怕可以也会导致层级太多,不例如扁平管理