BeanFactory和FactoryBean是Spring框架中名字相似但功能完全不同的两个核心接口,也是面试高频题之一。很多开发者容易混淆它们的作用,甚至误以为两者是“父子关系”。本文从源码层面解析两者的设计差异,并结合实际场景说明它们的用途,帮你彻底理清这两个概念!
一、BeanFactory:Spring的“大管家”
1. 核心职责
BeanFactory是Spring容器的根接口,负责管理所有Bean的生命周期和依赖关系。它是Spring IOC(控制反转)的核心实现,提供了以下能力:
-
创建Bean:根据配置或注解实例化Bean。
-
管理Bean:存储Bean定义(BeanDefinition)和Bean实例。
-
获取Bean:通过
getBean()
方法从容器中获取Bean。
2. 源码解析
BeanFactory
接口定义了一系列基础方法,核心代码如下:
public interface BeanFactory {
// 根据名称获取Bean实例
Object getBean(String name) throws BeansException;
// 判断Bean是否存在
boolean containsBean(String name);
// 获取Bean的类型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// 其他方法...
}
常见实现类:
-
DefaultListableBeanFactory
:Spring默认的Bean工厂实现。 -
ApplicationContext
(应用上下文):在BeanFactory基础上扩展了更多功能(如国际化、事件发布)。
二、FactoryBean:自定义Bean的“工厂”
1. 核心职责
FactoryBean是一个特殊的Bean接口,用于定制复杂对象的创建逻辑。当某个Bean的创建过程无法通过简单配置完成时(例如需要动态生成代理对象、连接外部资源等),可以通过实现FactoryBean
接口来自定义生成逻辑。
2. 源码解析
FactoryBean
接口定义了三个核心方法:
public interface FactoryBean<T> {
// 返回实际需要的Bean实例
T getObject() throws Exception;
// 返回Bean的类型
Class<?> getObjectType();
// 是否是单例
boolean isSingleton();
}
关键点:
-
当从BeanFactory中获取FactoryBean类型的Bean时,实际返回的是
getObject()
方法生成的实例。 -
如果想获取FactoryBean本身,需要在Bean名称前加
&
符号(例如&myFactoryBean
)。
三、BeanFactory vs FactoryBean:本质区别
对比项 | BeanFactory | FactoryBean |
---|---|---|
角色 | Spring容器的核心接口,管理所有Bean。 | 一个特殊的Bean,用于自定义其他Bean的创建。 |
功能 | Bean的创建、存储、管理。 | 定制单个Bean的创建逻辑。 |
使用场景 | 所有Bean的通用管理。 | 复杂对象创建(如MyBatis的SqlSessionFactory)。 |
获取方式 | 直接通过getBean("beanName") 获取Bean。 | 通过getBean("&factoryBeanName") 获取FactoryBean本身。 |
四、通过源码看FactoryBean的工作流程
假设有一个FactoryBean实现类MyFactoryBean
:
public class MyFactoryBean implements FactoryBean<User> {
@Override
public User getObject() {
return new User("Spring"); // 自定义创建User对象
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
1. 注册FactoryBean到容器
在Spring配置中声明:
<bean id="userFactory" class="com.example.MyFactoryBean"/>
2. 获取Bean的流程
-
获取User实例:调用
getBean("userFactory")
时,Spring会调用MyFactoryBean.getObject()
,返回User
对象。 -
获取FactoryBean本身:调用
getBean("&userFactory")
,返回MyFactoryBean
实例。
源码逻辑:
在AbstractBeanFactory
中,通过getObjectForBeanInstance
方法判断是否为FactoryBean:
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName) {
// 如果name以"&"开头,直接返回FactoryBean本身
if (BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
// 否则返回FactoryBean创建的Bean
if (beanInstance instanceof FactoryBean) {
return getObjectFromFactoryBean((FactoryBean<?>) beanInstance, name, beanName);
}
return beanInstance;
}
五、实际应用场景
场景1:动态代理对象生成
Spring的ProxyFactoryBean
用于创建AOP代理对象。例如:
<bean id="userServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="userService"/>
<property name="interceptorNames">
<list>
<value>myInterceptor</value>
</list>
</property>
</bean>
运行 HTML
-
通过
userServiceProxy
获取的是代理对象,而非ProxyFactoryBean
本身。
场景2:集成第三方框架
MyBatis的SqlSessionFactoryBean
是一个典型的FactoryBean,用于创建SqlSessionFactory
:
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
return factoryBean;
}
-
Spring容器中实际存储的是
SqlSessionFactory
实例,而非SqlSessionFactoryBean
。
六、常见问题与避坑指南
问题1:为什么获取FactoryBean时得到的是它创建的对象?
答案:Spring的设计规定,默认返回FactoryBean.getObject()
的结果。若需获取FactoryBean本身,需在Bean名称前加&
。
问题2:FactoryBean和@Bean注解有什么区别?
答案:
-
@Bean
注解用于配置类中定义Bean,创建逻辑由Spring处理。 -
FactoryBean
用于更复杂的创建逻辑(如条件判断、动态生成)。
问题3:FactoryBean能否依赖其他Bean?
答案:可以!FactoryBean本身是一个Bean,可以注入其他依赖,例如:
public class MyFactoryBean implements FactoryBean<User> {
@Autowired
private Environment env;
@Override
public User getObject() {
// 使用env配置信息创建User
return new User(env.getProperty("user.name"));
}
}
七、总结
-
BeanFactory:Spring容器的“大管家”,负责所有Bean的管理。
-
FactoryBean:一个“特殊员工”,负责定制某些Bean的创建过程。
-
核心区别:BeanFactory是容器级接口,FactoryBean是Bean级接口。