news 2026/6/15 15:57:14

Spring 的西西弗斯之石:理解 BeanFactory、FactoryBean 与 ObjectFactory

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring 的西西弗斯之石:理解 BeanFactory、FactoryBean 与 ObjectFactory

今天,代码又报错了。或者也许是昨天,我不清楚。
不管怎样,Spring 容器抛出了一个BeanCreationException。为了解决它,我被迫潜入框架的深处,去注视那些平时被@Autowired掩盖的齿轮。

在 Spring 的世界里,存在着一种必然的复杂性。这种复杂性并非设计者的恶趣味,而是为了在一个静态的语言中构建动态世界所付出的代价。

在这个庞大的机器中,有三个名字极其相似的概念经常被混淆:BeanFactoryFactoryBeanObjectFactory。这并不是命名的贫瘠,而是它们在本质上确实存在着微妙的纠缠。

今天,我们剥离掉那些花哨的比喻和无用的糖衣,用一种冷静的、近乎解剖学的视角,去审视这三个概念的本质。


一、BeanFactory:存在的容器

让我们首先纠正一个观念:BeanFactory 名为工厂,但其本质是容器(Container)。

当我们谈论 Spring 容器时,我们实际上是在谈论BeanFactory。它是 Spring IoC 容器的根接口,是整个世界的物理法则。

1.1 唯一的职责

它的定义极其克制。它不关心业务逻辑,只关心一件事:管理对象的生命周期

public interface BeanFactory { Object getBean(String name) throws BeansException; <T> T getBean(String name, Class<T> requiredType); boolean containsBean(String name); // ... }

当你启动一个 Spring Boot 应用时,ApplicationContext就像一个充满活力的城市,而BeanFactory则是支撑这座城市的地下管网。所有的 BeanDefinition(关于 Bean 应该如何创建的蓝图)都注册在这里。

1.2 残酷的现实

在大多数情况下,你不需要直接与BeanFactory对话。因为ApplicationContext已经为你封装好了一切。
但当你试图理解为什么你的 Bean 没有被正确初始化,或者为什么你的循环依赖失效时,你就必须意识到:你所有的 Bean,都只是BeanFactory中的 entries(条目)。

它是一个巨大的Map<String, BeanDefinition>Map<String, Object>的管理者。它冷酷无情,只按照定义的规则(Scope, Lazy, Dependence)来实例化对象。


二、FactoryBean:必要的欺骗

如果说BeanFactory是宏观规则的制定者,那么FactoryBean就是微观规则的潜行者

2.1 静态语言的困境

想象这样一个场景:你需要注入一个接口的实现,但这个实现类并不存在于代码中,它是通过动态代理在运行时生成的。
这在 RPC 框架(如 Dubbo、Feign)和 ORM 框架(如 MyBatis)中极其常见。

你无法通过简单的<bean class="...">@Component来描述一个“不存在的类”。
这时候,你需要一个中间人。这个中间人表面上是一个普通的 Bean,但实际上,它是一个工厂。

2.2 伪装的艺术:以 MyBatis 为例

为什么你只需要写一个UserMapper接口,就能直接@Autowired使用?
因为 Spring 容器里注册的那个 "userMapper" Bean,根本不是你的接口实现,而是一个MapperFactoryBean

// 简化的逻辑示意 public class MapperFactoryBean<T> implements FactoryBean<T> { private Class<T> mapperInterface; @Override public T getObject() throws Exception { // 往里跟进,最终这里发生了魔法:通过 JDK 动态代理生成接口的实 return (T) Proxy.newProxyInstance( mapperInterface.getClassLoader(), new Class[] { mapperInterface }, new MapperProxy<>() ); } @Override public Class<?> getObjectType() { return mapperInterface; } @Override public boolean isSingleton() { return true; } }

2.3 这里的真相

当容器调用getBean("userMapper")时,它发现这是一个FactoryBean。于是,它不会返回FactoryBean实例本身,而是默默地调用getObject(),并返回那个代理对象。

这就是欺骗。你以为你拿到了一个 Bean,其实你拿到的是 Bean 生产的产品。

如果你渴望看到真相,看到那个操纵傀儡的幕后黑手,你需要在 Bean 名称前加上&

// 获取的是 MapperProxy 代理对象 Object product = context.getBean("userMapper"); // 获取的是 FactoryBean 工厂本身 Object factory = context.getBean("&userMapper");

三、ObjectFactory:时间的延迟

BeanFactory负责掌控空间(容器),FactoryBean负责掌控构造(逻辑),而ObjectFactory则是为了掌控时间

3.1 循环的死结

在 Spring 的世界里,有一个经典的荒谬:A 需要 B,B 需要 A。
如果是构造器注入,只需坦然承认失败。但如果是 Setter 注入,Spring 试图挽救这种死结。

在 A 创建的过程中,需要注入 B。B 创建时,又需要注入 A。
此时 A 还在创建中,尚不是一个完整的 Bean。怎么办?
Spring 引入了三级缓存的概念。而第三级缓存,存放的就是一个ObjectFactory

3.2 回调的本质

ObjectFactory在源码中简单得令人发指:

@FunctionalInterface public interface ObjectFactory<T> { T getObject() throws BeansException; }

它只是一个函数式接口,一个回调。
它存在的意义在于:我现在不想要这个对象,但我想要一个“在未来某个时刻能获取这个对象”的能力。

在循环依赖中,Spring 提前暴露了一个ObjectFactory

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

当 B 需要 A 时,它通过这个ObjectFactory拿到了 A 的早期引用(Early Reference)。尽管 A 还没完全初始化好,但 B 已经可以持有它的引用了。死结解开了。

3.3 作用域的错位

另一个场景是:一个单例(Singleton)的 Service 需要使用一个 原型(Prototype)的 Bean。
如果你直接@Autowired,原型的 Bean 只有在 Service 创建时被注入一次,之后也就是永远同一个对象了。这违背了原型的初衷。

如何解决?使用ObjectFactory延迟获取。

@Service public class ReportService { @Autowired private ObjectFactory<ReportBuilder> builderFactory; public void generate() { // 每次调用 getObject(),容器都会创建一个全新的 ReportBuilder ReportBuilder builder = builderFactory.getObject(); builder.build(); } }

在这里,ObjectFactory就像是一个通往容器的句柄,让你随时可以伸手进去拿一个新的对象,而不是守着陈旧的缓存。


四、审判与裁决

让我们在最后,用最客观的表格来审判这三者的区别。这不是为了背诵,而是为了理清混乱。

维度BeanFactoryFactoryBeanObjectFactory
存在形式容器(Container)Bean(Component)接口(Interface/Callback)
底层逻辑ApplicationContext的父级接口 /宏观工厂实现了FactoryBean接口的类 /微观工厂函数式接口 /延迟回调
核心职责管理所有 Bean 的生命周期此 Bean 负责生产另一个复杂的 Bean封装对象的创建过程,提供延迟获取能力
获取方式ApplicationContext是它的超集getBean("name")拿产品
getBean("&name")拿工厂
注入ObjectFactory<T>后调用getObject()
真实场景Spring 框架的基石MybatisMapperFactoryBean,ProxyFactoryBean解决循环依赖(三级缓存), Scope(原型模式)适配

五、结语

在代码的荒原上,我们通过构建抽象来对抗混乱。

  • BeanFactory是我们脚下的大地。它被称为工厂,但它实际是孕育万物的土壤(容器)。
  • FactoryBean是我们手中的精密机床。它是一个特殊的 Bean,存在的目的却是为了制造另一个 Bean。
  • ObjectFactory是我们预留的时间胶囊。它只是一个单纯的接口,为了应对循环与未来的不确定性。

理解它们,并不是为了通过面试,而是为了在下一次抛出异常时,你能冷静地凝视堆栈信息,知道机器的哪个齿轮发生了错位。

既然我们选择了与机器共舞,就必须理解机器的逻辑。这或许就是作为开发者的西西弗斯式命运——我们需要一次又一次地将巨石推向山顶,以此证明我们对这个庞大系统的掌控

本文通过 AI 润色(加缪风格),试图以一种冷静、客观甚至存在主义的视角,去解构这些在日常 Coding 中被我们习以为常的概念。希望这种独特的叙事风格,能让你对这些枯燥的技术概念有更深刻的“存在感”。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/6 4:31:13

基于单片机无线公交车人数统计装置系统设计

**单片机设计介绍&#xff0c;基于单片机无线公交车人数统计装置系统设计 文章目录一 概要二、功能设计设计思路三、 软件设计原理图五、 程序一 概要 基于单片机无线公交车人数统计装置系统设计概要如下&#xff1a; 一、系统概述 本系统采用单片机作为核心控制器&#xff0…

作者头像 李华
网站建设 2026/6/15 13:18:34

基于单片机无线智能输液控制器系统设计

**单片机设计介绍&#xff0c;基于单片机无线智能输液控制器系统设计 文章目录一 概要二、功能设计设计思路三、 软件设计原理图五、 程序一 概要 基于单片机无线智能输液控制器系统设计概要如下&#xff1a; 一、系统概述 本系统旨在通过单片机技术结合无线通信技术&#xf…

作者头像 李华
网站建设 2026/6/15 15:15:25

网络安全技术硬核盘点:一文讲透主流攻防体系与高能总结

网络安全技术虽然非常复杂&#xff0c;但是归纳起来&#xff0c;主要就是为了解决以下三方面问题&#xff1a; 1.数据的机密性&#xff1a;即如何令人们发送数据&#xff0c;即使被其他无关人员截取&#xff0c;他们也无法获知数据的含义。 2.数据的有效性&#xff1a;指数据不…

作者头像 李华
网站建设 2026/6/15 12:15:03

网络安全检测实战核心技术深度解析:从入侵识别到威胁感知体系的构建

一&#xff0c;网络安全漏洞 安全威胁是指所有能够对计算机网络信息系统的网络服务和网络信息的机密性&#xff0c;可用性和完整性产生阻碍&#xff0c;破坏或中断的各种因素。安全威胁可分为人为安全威胁和非人为安全威胁两大类。 1&#xff0c;网络安全漏洞威胁 漏洞分析的…

作者头像 李华