← 返回题目列表

BeanFactory、ApplicationContext 和 FactoryBean 有什么区别?

高频 中等 第 7 / 30 题 更新于 2026/07/26
SpringBeanFactoryApplicationContextFactoryBean

简化版

BeanFactory 是 Spring IoC 容器的基础接口,ApplicationContext 在它之上增加事件、国际化、资源加载、环境与自动注册常用后处理器等企业级能力。FactoryBean<T> 不是容器,而是一个特殊 Bean:容器通过它的 getObject() 暴露复杂产品对象,使用 &beanName 才能取得工厂本身。

详细版

ApplicationContext 继承 BeanFactory,普通应用应优先使用它。BeanFactory 描述获取 Bean、查询类型和作用域等核心能力;ApplicationContext 还整合 ApplicationEventPublisherMessageSourceResourcePatternResolverEnvironmentCapable 等接口,并负责更完整的容器启动流程。

FactoryBean 用于把复杂对象的创建逻辑接入容器,例如某些代理、客户端或框架基础设施。Bean 名称为 client 时,getBean("client") 得到其产品,getBean("&client") 得到 FactoryBean;它和“创建 Bean 的 BeanFactory”不是同一个层次的概念。

完整版教学

一、BeanFactory 是容器能力的根

BeanFactory 最核心的职责是根据名称或类型提供 Bean,并管理依赖关系、作用域和生命周期。它定义的是容器对外的基本契约,具体注册 BeanDefinition、创建单例和处理依赖的工作由其实现完成。

UserService service = beanFactory.getBean(UserService.class);
boolean exists = beanFactory.containsBean("userService");

日常业务代码不应到处主动调用 getBean(),否则会从依赖注入退回服务定位器模式;这里的 API 更多用于框架集成和理解容器边界。

二、ApplicationContext 增加了什么

ApplicationContext 是更完整的应用容器,除 BeanFactory 能力外,还提供:

  • 发布和监听应用事件;
  • 国际化消息解析;
  • 统一的资源与通配路径加载;
  • Environment、Profile 和属性源访问;
  • 更方便的注解扫描及后处理器集成。

常见实现包括 AnnotationConfigApplicationContext,Web MVC 中则使用 WebApplicationContext。现代 Spring 应用通常不会直接实例化一个裸 BeanFactory。

三、不要死背“懒加载与立即加载”

经典面试答案常说 BeanFactory 懒加载、ApplicationContext 启动时立即创建 Bean,这不够准确。是否预实例化单例取决于具体容器实现和刷新流程:ApplicationContext 默认在 refresh() 后预实例化非 lazy 的 singleton,但标记 @Lazy 的 Bean 仍可延迟创建;BeanFactory 也可以显式调用预实例化逻辑。

真正稳定的区别是接口能力和启动管理方式,而不是把二者简单等同于“懒”与“饿”。

四、FactoryBean 如何生产对象

class ClientFactoryBean implements FactoryBean<Client> {
    @Override
    public Client getObject() {
        return new Client("https://api.example.com");
    }

    @Override
    public Class<?> getObjectType() {
        return Client.class;
    }
}

FactoryBean 自身仍由容器管理,但正常按 Bean 名获取时,容器返回 getObject() 的结果。getObjectType() 帮助容器在产品尚未创建时进行类型匹配;isSingleton() 用来说明 FactoryBean 返回的产品是否按单例语义管理,默认值是 true

五、FactoryBean 与 @Bean 工厂方法

两者都能封装对象创建过程,但使用场景不同。@Bean 方法更直观,适合应用配置;FactoryBean 是容器级扩展协议,适合框架需要以统一方式暴露复杂产品对象时使用。

还要区分 FactoryBean 的产品单例与 FactoryBean 自身的作用域。工厂 Bean 可以是 singleton,但它声明返回的产品不一定是 singleton;判断时要同时看 BeanDefinition 作用域和 isSingleton() 语义。

六、用启动与取对象流程区分三者

ApplicationContext.refresh() 会准备 BeanFactory、注册后处理器、初始化事件与消息资源,并在末段预实例化非懒加载 singleton;这解释了为什么配置错误经常在应用启动时暴露。一个容器里假设有 200 个非懒 singleton 和 20 个 @Lazy singleton,刷新阶段通常会主动创建前 200 个;后 20 个若未被非懒 Bean 的依赖链提前拉起,则在首次需要时创建;这只是默认行为,不是 BeanFactory 与 ApplicationContext 的接口定义本身。

ApplicationContext.refresh()

        ├─ 配置并驱动内部 BeanFactory
        ├─ 注册 BeanPostProcessor / 事件等基础设施
        └─ 预实例化非 lazy singleton

getBean("client")  ──> FactoryBean.getObject() ──> Client 产品
getBean("&client") ─────────────────────────────> FactoryBean 本身
名称它是什么面试时最关键的边界
BeanFactoryIoC 容器基础契约定义 Bean 获取、类型、作用域等核心能力
ApplicationContext完整应用上下文继承 BeanFactory,并驱动完整启动和企业级能力
FactoryBean<T>容器管理的特殊 Bean普通名字暴露产品,& 前缀取得工厂

易错点:FactoryBean 的 isSingleton() 描述的是产品是否可按单例语义缓存,不等于 FactoryBean 自身的 BeanDefinition 一定是 singleton。

七、常见误区与追问

  • 误区:BeanFactory 一定懒加载,ApplicationContext 一定饿加载。 预实例化取决于具体实现、刷新流程和 lazy 配置,稳定区别是接口能力与上下文启动职责。
  • 误区:FactoryBean 就是 BeanFactory 的实现。 前者是生产某种产品对象的扩展协议,后者是管理 Bean 的容器基础接口,层次完全不同。
  • 误区:FactoryBean 的 isSingleton 返回 false 就必然每次得到全新独立对象。 它只否定单例缓存语义;若要明确原型语义,还要结合实现及 SmartFactoryBean 等契约判断。
  • 追问:为什么 getObjectType 很重要? 容器可能在产品尚未创建时做按类型查询和自动装配;返回准确类型能避免该 FactoryBean 被类型匹配忽略。
  • 追问:FactoryBean 生产对象的销毁由谁负责? 容器主要管理 FactoryBean 自身;工厂若持有需关闭的产品资源,通常应在自身销毁回调中负责委托清理。
  • 追问:业务配置优先用 @Bean 还是 FactoryBean? 普通应用对象优先选择直观的 @Bean;需要接入容器级产品语义、延迟类型判断或框架基础设施时再考虑 FactoryBean。

八、加强记忆

BeanFactory 是 IoC 容器的基础契约,ApplicationContext 是日常应用使用的完整容器;FactoryBean 则是容器管理的特殊工厂对象。普通名字取产品,&名字 取工厂本身;不要再用“一个懒加载、一个立即加载”概括全部区别。