BeanFactory 和 FactroyBean 的关系?
面试考察点
-
概念辨析能力:面试官不仅仅是想听你背定义,更是想看你能不能把名字这么像的两个接口区分清楚,而不是含含糊糊说 "差不多"。
-
IoC 容器理解深度:
BeanFactory是 Spring IoC 容器的根接口,你能不能说清楚它在容器体系中扮演的角色,直接反映了你对 Spring 底层的理解程度。 -
扩展机制认知:
FactoryBean是 Spring 留给开发者的一个重要扩展点。知道它、用过它,说明你不仅仅停留在 "加注解" 的层面,而是真的深入过 Spring。
核心答案
先上一张对比表,一目了然:
| 维度 | BeanFactory | FactoryBean |
|---|---|---|
| 是什么 | IoC 容器的 顶层接口 | 一个 特殊的 Bean |
| 职责 | 管理、创建、装配所有 Bean | 创建某个 复杂对象 的工厂 |
| 谁用谁 | 容器本身 | 被 BeanFactory 管理 |
| 数量 | 整个容器只有 一个 | 可以有 多个 |
| 典型实现 | DefaultListableBeanFactory | SqlSessionFactoryBean、FeignClientFactoryBean |
| 设计模式 | 工厂模式 | 工厂方法模式 |
一句话总结:BeanFactory 是生产 Bean 的工厂,FactoryBean 是工厂里的一个特殊工人,专门负责生产某种复杂产品。
深度解析
一、BeanFactory —— Spring 的 "总工厂"
BeanFactory 是 Spring IoC 容器的最底层接口,说白了就是整个 Bean 管理体系的地基。
public interface BeanFactory {
// 核心 API:根据名字获取 Bean
Object getBean(String name) throws BeansException;
// 根据类型获取 Bean
<T> T getBean(Class<T> requiredType) throws BeansException;
// 判断是否包含某个 Bean
boolean containsBean(String name);
// 判断是否单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// ...
}
它只定义了 IoC 容器的最基本行为:获取 Bean、判断 Bean 的作用域等。实际开发中我们很少直接用它,更多用的是它的子接口 ApplicationContext,功能更丰富。
上图的层次关系:
BeanFactory:只管 "拿 Bean",是最精简的接口定义。ListableBeanFactory:在BeanFactory基础上增加了批量操作能力,比如getBeansOfType()可以一次拿到某个类型的所有 Bean。HierarchicalBeanFactory:支持父子容器体系,Spring MVC 中就是靠这个实现Controller层和Service层的 Bean 隔离。ApplicationContext:集大成者,不仅有 Bean 管理能力,还有事件发布、国际化、资源加载等功能。- 真正干活的是
DefaultListableBeanFactory,它是整个体系中功能最完整的实现类。
二、FactoryBean —— 特殊的 "定制工人"
为什么要搞个 FactoryBean?因为有些 Bean 的创建过程太复杂了,用普通的构造函数或者 @Bean 方法搞不定。
比如 MyBatis 的 SqlSessionFactory,创建它需要配置数据源、插件、别名、Mapper…… 写个 @Bean 方法几百行,太丑了。Spring 说:那这样吧,你实现 FactoryBean 接口,把创建逻辑封装进去,剩下的我来管。
public interface FactoryBean<T> {
// 返回创建的对象(这才是真正放进容器的 Bean)
T getObject() throws Exception;
// 返回对象的类型
Class<?> getObjectType();
// 是否单例(默认 true)
default boolean isSingleton() {
return true;
}
}
来看一个实际例子,自己写一个 FactoryBean:
// 1. 自定义 FactoryBean
@Component
public class MyFactoryBean implements FactoryBean<Connection> {
@Override
public Connection getObject() throws Exception {
// 复杂的创建逻辑:加载驱动、配置连接池、设置参数...
String url = "jdbc:mysql://localhost:3306/mydb";
return DriverManager.getConnection(url, "root", "123456");
}
@Override
public Class<?> getObjectType() {
return Connection.class;
}
}
// 2. 使用时直接注入,拿到的是 Connection,不是 MyFactoryBean
@Service
public class UserService {
@Autowired
private Connection connection; // 注入的是 getObject() 返回的对象
}
这里有个很容易搞混的点,我当年学的时候也迷糊了好一阵。
三、关键区别:注册的是谁,拿到的是谁?
上图把核心区别说清楚了:
- 普通 Bean:注册什么类型,
getBean()就返回什么类型。注册MyService,拿到MyService。 - FactoryBean:注册的是
MyFactoryBean,但getBean("myFactoryBean")返回的却是getObject()的结果,也就是Connection。Spring 偷偷帮你调了一层。 - 想要 FactoryBean 本身:在 Bean 名字前面加个
&前缀,getBean("&myFactoryBean")就能拿到MyFactoryBean实例。这个&的设计源自BeanFactory接口里定义的一个常量FACTORY_BEAN_PREFIX = "&"。
四、FactoryBean 的经典应用场景
面试中能说出几个 Spring 生态中的实际应用,加分不少:
| 框架 | FactoryBean 实现 | 创建的对象 |
|---|---|---|
| MyBatis-Spring | SqlSessionFactoryBean | SqlSessionFactory |
| Spring-Cloud-OpenFeign | FeignClientFactoryBean | Feign 代理对象 |
| Spring 事务 | TransactionProxyFactoryBean | 事务代理对象 |
| Spring AOP | ProxyFactoryBean | AOP 代理对象 |
你看,这些框架里的核心对象,创建过程都很复杂,全部交给 FactoryBean 来封装。对外只暴露一个简单的 Bean 名称,内部怎么做的不用你操心。
五、常见误区
这块有个经典坑。很多人以为 FactoryBean 本身不会被 Spring 管理——错了。FactoryBean 本身也是一个 Bean,它会被 BeanFactory 完整地管理(依赖注入、生命周期回调等),只不过当其他 Bean 通过 getBean() 获取它时,返回的是 getObject() 的结果而已。
@Component
public class MyFactoryBean implements FactoryBean<UserService> {
// FactoryBean 本身的属性也能被注入
@Autowired
private DataSource dataSource;
@Override
public UserService getObject() {
// 可以用注入的依赖来构建复杂对象
return new UserService(dataSource);
}
@Override
public Class<?> getObjectType() {
return UserService.class;
}
}
面试高频追问
-
BeanFactory和ApplicationContext有什么区别?BeanFactory是最基础的容器接口,懒加载,按需创建 Bean。ApplicationContext是它的超集,支持事件发布、国际化、AOP 自动代理、资源加载等,而且默认预加载所有单例 Bean。日常开发用ApplicationContext,某些对内存极度敏感的场景可以考虑BeanFactory。
-
FactoryBean的isSingleton()返回 false 会怎样?- 每次
getBean()都会调用一次getObject(),创建一个新对象。Spring 不会缓存它,适合创建非单例的复杂对象(比如原型作用域的连接对象)。
- 每次
-
为什么要用
FactoryBean而不是@Bean方法?- 简单场景用
@Bean就够了。但如果创建逻辑需要框架级别的抽象(比如 MyBatis、Feign 这种需要大量配置的场景),FactoryBean更合适,因为它是一个独立的组件,可以被其他机制(如BeanPostProcessor)感知和处理。另外FactoryBean支持泛型,类型推断更精准。
- 简单场景用
常见面试变体
- "
FactoryBean和BeanFactory有什么区别?" - "Spring 中
FactoryBean有什么用?你在项目中用过吗?" - "MyBatis 是怎么和 Spring 整合的?"(本质就是
SqlSessionFactoryBean) - "
getBean("&xxx")是什么意思?"
记忆口诀
"BeanFactory 是大工厂,FactoryBean 是小工人;大工厂管所有人,小工人专做复杂活。"
总结
BeanFactory 是 Spring IoC 容器的根基,负责管理所有 Bean 的生命周期;FactoryBean 是一个特殊的 Bean,用来封装复杂对象的创建逻辑。它俩不是 "二选一" 的关系,而是 "管理者" 和 "被管理者" 的关系——FactoryBean 本身就被 BeanFactory 管理,只不过别人拿它的时候,拿到的是它生产的产品,不是它自己。面试中把这个关系说清楚,再把 & 前缀的细节一补充,面试官基本就满意了。
