BeanFactory 和 FactoryBean 的关系?
结论先行:名字颠倒,职责完全不同。BeanFactory 是容器本身——IoC 的顶层接口,负责"管理 Bean"(getBean、作用域、生命周期);FactoryBean 是容器里的一个 Bean——负责"生产 Bean",当某个对象构造过程复杂或需要代理时,把构造逻辑写进 getObject()。二者是"仓库"与"仓库里的制造机"的关系,不是继承也不是别名。
一、本质对比
| 维度 | BeanFactory | FactoryBean |
|---|---|---|
| 身份 | 容器接口(org.springframework.beans.factory.BeanFactory) | 普通 Bean,实现 FactoryBean<T> 接口 |
| 职责 | 管理 Bean 定义、创建、注入、作用域 | 生产某个复杂对象 |
| 关键方法 | getBean、getBeanProvider、containsBean | getObject()、getObjectType()、isSingleton() |
| 实现类举例 | DefaultListableBeanFactory | SqlSessionFactoryBean、MapperFactoryBean、RpcProxyFactoryBean |
| 数量 | 一个应用通常一个 | 容器里可以有任意多个 |
| 谁调用谁 | 容器调用 FactoryBean 的 getObject() | 被容器管理,产出物交给容器 |
二、& 前缀:一个名字两个对象
容器中 Bean 名 "userMapper":
getBean("userMapper") → FactoryBean#getObject() 的返回值(UserMapper 代理)
getBean("&userMapper") → FactoryBean 实例本身(MapperFactoryBean)
推理过程:
BeanFactory#getBean 先查 singletonObjects
→ 命中且是 FactoryBean → 返回 getObject()
→ 名字以 & 开头 → 去掉 & 后返回 FactoryBean 本身
三、自定义 FactoryBean
public class RpcProxyFactoryBean<T> implements FactoryBean<T>, BeanFactoryAware {
private Class<T> interfaceClass;
private String serviceUrl;
private BeanFactory beanFactory;
@Override
@SuppressWarnings("unchecked")
public T getObject() {
// 复杂构造:生成动态代理,把远程调用伪装成本地接口
return (T) Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class<?>[]{interfaceClass},
(proxy, method, args) -> invokeRemote(serviceUrl, method, args));
}
@Override
public Class<?> getObjectType() {
return interfaceClass;
}
@Override
public boolean isSingleton() {
return true; // 单例则 getObject 只调用一次,结果被缓存
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void setInterfaceClass(Class<T> c) { this.interfaceClass = c; }
public void setServiceUrl(String url) { this.serviceUrl = url; }
}
@Configuration
public class RpcConfig {
@Bean
public RpcProxyFactoryBean<UserService> userServiceProxy() {
RpcProxyFactoryBean<UserService> f = new RpcProxyFactoryBean<>();
f.setInterfaceClass(UserService.class);
f.setServiceUrl("http://user-svc");
return f;
}
}
四、真实案例:MyBatis 的 Mapper
MyBatis 的 Mapper 只有接口、没有实现类,正是靠 MapperFactoryBean 把接口"变成"可注入的代理:
@MapperScan("com.demo.mapper")
└─ MapperScannerConfigurer(BeanDefinitionRegistryPostProcessor)
└─ 为每个接口注册一个 MapperFactoryBean 的 BeanDefinition
└─ 容器 getBean("userMapper")
└─ MapperFactoryBean#getObject() → JDK 动态代理
└─ 方法调用被代理拦截,转成 SqlSession 的 SQL 执行
五、常见追问
- 问:FactoryBean 的
getObject()什么时候执行? 首次getBean或被注入时;isSingleton()为 true 时会被缓存,为 false 则每次都调用。 - 问:FactoryBean 和
@Bean方法有什么区别?@Bean方法在配置类解析阶段就被调用并注册实例;FactoryBean 注册的是"工厂",真实对象延迟到getObject()。 - 问:
getObjectType()返回 null 会怎样? 容器无法提前判断类型,会提前调用getObject()来探测,可能带来副作用或提前初始化。 - 问:BeanFactory 与 ApplicationContext 什么关系? 后者继承前者并增强(事件、国际化、资源、AOP 集成、自动注册 BPP),BeanFactory 是最小契约。
- 问:能用 FactoryBean 做对象池吗? 勉强可以,但更推荐
@Bean+ 池化组件,FactoryBean 适合"创建逻辑与业务无关"的场景。
小结
一句话:BeanFactory 是容器,FactoryBean 是容器里的工厂;前者管所有 Bean,后者只产出自己那一个对象。 记住 & 前缀与 getObject() 的延迟语义,再加 MyBatis Mapper 这个实例,基本就够用了。