今天,代码又报错了。或者也许是昨天,我不清楚。
不管怎样,Spring 容器抛出了一个BeanCreationException。为了解决它,我被迫潜入框架的深处,去注视那些平时被@Autowired掩盖的齿轮。
在 Spring 的世界里,存在着一种必然的复杂性。这种复杂性并非设计者的恶趣味,而是为了在一个静态的语言中构建动态世界所付出的代价。
在这个庞大的机器中,有三个名字极其相似的概念经常被混淆:BeanFactory、FactoryBean和ObjectFactory。这并不是命名的贫瘠,而是它们在本质上确实存在着微妙的纠缠。
今天,我们剥离掉那些花哨的比喻和无用的糖衣,用一种冷静的、近乎解剖学的视角,去审视这三个概念的本质。
一、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就像是一个通往容器的句柄,让你随时可以伸手进去拿一个新的对象,而不是守着陈旧的缓存。
四、审判与裁决
让我们在最后,用最客观的表格来审判这三者的区别。这不是为了背诵,而是为了理清混乱。
| 维度 | BeanFactory | FactoryBean | ObjectFactory |
|---|---|---|---|
| 存在形式 | 容器(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 中被我们习以为常的概念。希望这种独特的叙事风格,能让你对这些枯燥的技术概念有更深刻的“存在感”。