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 的关系?

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

  • 国际化(MessageSource)
  • 事件发布(ApplicationEventPublisher)
  • 资源加载(ResourcePatternResolver)
  • 自动装配 BeanPostProcessor、BeanFactoryPostProcessor
  • 启动时预加载所有单例 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 SqlSessionFactoryBean、ProxyFactoryBean
面试频率 高 高

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

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

相关推荐
长安米粒贵5 小时前
接口超时了,为什么重试反而把系统打垮?聊聊超时预算的 4 个误区
后端
骉马代驾5 小时前
代驾系统长连接实战(二):心跳、断线重连与消息补偿的完整实现
java
程序员Sunday5 小时前
Spring @Transactional 没回滚?按代理调用、异常和传播行为排查
java·后端·spring
付威20235 小时前
我用 100 行核心代码,做了一个能接入飞书的 Hermes 式智能体
人工智能·后端
java资料站5 小时前
案例:Spring Ai/Alibaba《模拟面试器》项目案例
人工智能·spring·面试
苏三说技术6 小时前
为什么越来越多人用 ZXing?
后端
冰暮流星6 小时前
sql之is null 运算符
java·数据库·sql
Rain的Java大神之路6 小时前
🔥13年Java老兵转型AI Agent:90%的人挂在同一个坑,根本不用学Python!(万字实战复盘,建议收藏)
java·后端·面试
yuniko-n6 小时前
【Java】关于容器选型:Deque、PriorityQueue、LinkedList
java·开发语言
IT小番茄6 小时前
用Codex搭可视化大屏工作流 15个行业场景设计稿看完直接抄作业
后端