BeanFactory 与 FactoryBean 的区别:面试深度解析

BeanFactory 与 FactoryBean 的区别:面试深度解析

这是 Spring 面试中出镜率极高的一道题。两个名字长得像,但职责完全不同。很多人背了答案,面试官一追问就露馅。本文从定义、职责、用法、源码和常见追问几个角度,把这两个概念彻底讲清楚。

一、一句话区分

  • BeanFactory :Spring 的 IoC 容器,负责管理所有 Bean 的创建、依赖注入和生命周期。
  • FactoryBean :一个特殊的 Bean,用于定制某个复杂对象的创建逻辑,它本身由 BeanFactory 管理。

简单说:BeanFactory 是"工厂",FactoryBean 是"工厂生产的特殊产品"。

二、BeanFactory 详解

2.1 定义

BeanFactory 是 Spring IoC 容器的顶层接口,定义了容器的最基本行为:

java 复制代码
public interface BeanFactory {
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    boolean containsBean(String name);
    boolean isSingleton(String name);
    boolean isPrototype(String name);
    Class<?> getType(String name);
    // ...
}

它提供了 getBean()containsBean()isSingleton() 等核心方法,是 Spring 管理 Bean 的基础设施。

2.2 常见实现

  • DefaultListableBeanFactory:最核心的实现,功能最完整。
  • XmlBeanFactory:基于 XML 配置的容器(已过时)。
  • AnnotationConfigApplicationContext:基于注解配置的容器,是 ApplicationContext 的实现。

2.3 职责

  • 读取配置(XML、注解、Java 配置)生成 BeanDefinition。
  • 实例化 Bean。
  • 依赖注入。
  • 管理 Bean 的作用域和生命周期。
  • 提供 getBean() 供外部获取 Bean。

2.4 使用示例

java 复制代码
BeanFactory factory = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = factory.getBean(UserService.class);

三、FactoryBean 详解

3.1 定义

FactoryBean 是一个接口,用于创建复杂的 Bean。它本身也是一个 Bean,由 Spring 容器管理,但通过 getBean() 获取它时,返回的是 getObject() 方法创建的对象,而不是 FactoryBean 本身。

java 复制代码
public interface FactoryBean<T> {
    T getObject() throws Exception;
    Class<?> getObjectType();
    boolean isSingleton();
}

3.2 三个方法

  • getObject():返回真正需要的对象。
  • getObjectType():返回对象的类型。
  • isSingleton():返回对象是否为单例。

3.3 使用示例

假设我们需要创建一个复杂的 Connection 对象,创建过程很繁琐,可以用 FactoryBean 封装:

java 复制代码
public class ConnectionFactoryBean implements FactoryBean<Connection> {
    
    @Override
    public Connection getObject() throws Exception {
        // 复杂的创建逻辑
        Connection conn = DriverManager.getConnection("jdbc:mysql://...");
        // 其他初始化
        return conn;
    }
    
    @Override
    public Class<?> getObjectType() {
        return Connection.class;
    }
    
    @Override
    public boolean isSingleton() {
        return true;
    }
}

在 XML 中注册:

xml 复制代码
<bean id="connection" class="com.example.ConnectionFactoryBean"/>

获取时:

java 复制代码
// 获取的是 getObject() 返回的 Connection 对象
Connection conn = context.getBean("connection", Connection.class);

// 获取 FactoryBean 本身,需要在 beanName 前加 &
ConnectionFactoryBean factoryBean = 
    context.getBean("&connection", ConnectionFactoryBean.class);

3.4 典型应用

  • MyBatis 的 SqlSessionFactoryBean :用于创建 SqlSessionFactory
  • Spring 的 ProxyFactoryBean:用于创建 AOP 代理对象。
  • JndiObjectFactoryBean:用于从 JNDI 获取对象。

四、核心区别对比

对比维度 BeanFactory FactoryBean
本质 IoC 容器顶层接口 一个特殊的 Bean
职责 管理所有 Bean 的创建、依赖注入、生命周期 定制某个复杂对象的创建逻辑
获取方式 getBean("beanName") 获取容器中的 Bean getBean("beanName") 返回 getObject() 的结果;getBean("&beanName") 返回 FactoryBean 本身
是否由容器管理 本身就是容器 是一个 Bean,由容器管理
实现方式 有多个实现类,如 DefaultListableBeanFactory 由开发者实现接口,注册为 Bean
使用场景 所有 Spring 应用的基础设施 创建复杂对象、集成第三方框架、创建代理对象
数量 一个应用通常一个容器 可以有多个 FactoryBean
生命周期 容器级 Bean 级,受容器管理

五、源码层面:getBean 如何处理 FactoryBean

当调用 getBean("connection") 时,Spring 会检查这个 Bean 是否实现了 FactoryBean 接口:

java 复制代码
// AbstractBeanFactory.getObjectForBeanInstance 简化逻辑
if (beanInstance instanceof FactoryBean) {
    if (!(name.startsWith("&"))) {
        // 返回 getObject() 创建的对象
        return ((FactoryBean<?>) beanInstance).getObject();
    } else {
        // 返回 FactoryBean 本身
        return beanInstance;
    }
}

如果 beanName 以 & 开头,返回 FactoryBean 本身;否则返回 getObject() 的结果。这就是 getBean("&connection") 能拿到 FactoryBean 的原因。

六、常见面试追问

1. BeanFactory 和 ApplicationContext 的关系?

ApplicationContextBeanFactory 的子接口,继承了 BeanFactory 的所有能力,并增加了:

  • 国际化(MessageSource)
  • 事件发布(ApplicationEventPublisher)
  • 资源加载(ResourcePatternResolver)
  • 自动装配 BeanPostProcessorBeanFactoryPostProcessor
  • 启动时预加载所有单例 Bean(BeanFactory 默认懒加载)

ApplicationContext 是面向应用开发的容器,BeanFactory 是底层基础设施。

2. 如何获取 FactoryBean 本身?

在 beanName 前加 &

java 复制代码
ConnectionFactoryBean factoryBean = context.getBean("&connection", ConnectionFactoryBean.class);

3. FactoryBean 和 @Bean 的区别?

  • @Bean 是方法级别的注解,在 @Configuration 类中定义 Bean。
  • FactoryBean 是类级别的接口,用于创建复杂对象,通常用于框架集成。
  • @Bean 更简洁,FactoryBean 更灵活,适合复杂的创建逻辑。

4. FactoryBean 的 isSingleton() 返回 true 时,getObject() 会被调用几次?

如果 isSingleton() 返回 true,Spring 会缓存 getObject() 的结果,多次获取返回同一个对象。如果返回 false,每次 getBean() 都会调用 getObject() 创建新对象。

5. 为什么 MyBatis 用 FactoryBean?

MyBatis 的 SqlSessionFactory 创建过程复杂,需要配置数据源、MyBatis 配置、Mapper 扫描等。用 FactoryBean 把这些逻辑封装起来,Spring 只需要管理 SqlSessionFactoryBean,通过它获取 SqlSessionFactory

七、总结

维度 BeanFactory FactoryBean
是什么 IoC 容器 创建复杂对象的特殊 Bean
核心方法 getBean() getObject()
获取方式 getBean("name") getBean("name") 返回产品,getBean("&name") 返回自身
谁管理 本身是容器 由 BeanFactory 管理
典型实现 DefaultListableBeanFactory SqlSessionFactoryBeanProxyFactoryBean
面试频率

记住一句口诀:BeanFactory 是容器,FactoryBean 是产品。容器管所有,产品管一个。

理解这两者的区别,不仅能应对面试,更能帮你理解 Spring 框架的设计思想------容器与扩展点分离,基础设施与业务逻辑解耦。

相关推荐
IT 行者1 小时前
JDK 27 正式发布:内存、安全、并发三路齐发
java
mldong1 小时前
一套审批流要写多少代码:13 个框架的接入 diff 我数了一遍,最少 422 行,最多 1798 行
后端·架构
伍一514 小时前
hiprint-spring-boot打印组件介绍
java·hiprint
Wang's Blog9 小时前
Java 接入Redis: 服务启动停止与后台运行配置
java·服务器·redis
此时不提桶,更待何时10 小时前
01-04-B-垃圾回收面试与生产事故实战
java·jvm·面试
GreenTea10 小时前
GrokBot 核心成员 Lauren Tan:每月交付 2000 个 PR 的人,是怎么用 AI 的
前端·后端·架构
码事漫谈10 小时前
FDE:一个缩写,两种命运
后端
名字还没想好☜11 小时前
Go context.AfterFunc 实战(Go 1.21):context 一取消就自动跑清理,告别手写 goroutine 监听 Done
后端·golang·go