BeanFactory 和 FactroyBean 的关系?


一则或许对你有用的小广告

欢迎加入小哈的星球,你将获得:专属的实战项目(4个项目都能学) / 1v1 提问 / 简历修改 / Java 学习路线 / 社群讨论 / 学习打卡 / 每月赠书

  • 《Spring AI 项目实战(问答机器人、RAG 智能客服、联网搜索)》已完结,基于 Spring AI + Spring Boot 3.x + JDK 21...查看介绍

  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...查看介绍;演示链接:http://116.62.199.48:7070/

  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接:http://116.62.199.48/

  • 新开坑项目:《从零手撸:秒杀系统高并发优化实战》 正在更新中...,查看介绍

截止目前,星球内专栏累计输出 150w+ 字,讲解图 5110+ 张,还在持续爆肝中.. 后续还会上新更多项目,已有 4700+ 小伙伴加入学习,欢迎点击围观

面试考察点

  1. 概念辨析能力:面试官不仅仅是想听你背定义,更是想看你能不能把名字这么像的两个接口区分清楚,而不是含含糊糊说 "差不多"。

  2. IoC 容器理解深度BeanFactory 是 Spring IoC 容器的根接口,你能不能说清楚它在容器体系中扮演的角色,直接反映了你对 Spring 底层的理解程度。

  3. 扩展机制认知FactoryBean 是 Spring 留给开发者的一个重要扩展点。知道它、用过它,说明你不仅仅停留在 "加注解" 的层面,而是真的深入过 Spring。

核心答案

先上一张对比表,一目了然:

维度 BeanFactory FactoryBean
是什么 IoC 容器的 顶层接口 一个 特殊的 Bean
职责 管理、创建、装配所有 Bean 创建某个 复杂对象 的工厂
谁用谁 容器本身 BeanFactory 管理
数量 整个容器只有 一个 可以有 多个
典型实现 DefaultListableBeanFactory SqlSessionFactoryBeanFeignClientFactoryBean
设计模式 工厂模式 工厂方法模式

一句话总结: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;
    }
}

面试高频追问

  1. BeanFactoryApplicationContext 有什么区别?

    • BeanFactory 是最基础的容器接口,懒加载,按需创建 Bean。ApplicationContext 是它的超集,支持事件发布、国际化、AOP 自动代理、资源加载等,而且默认预加载所有单例 Bean。日常开发用 ApplicationContext,某些对内存极度敏感的场景可以考虑 BeanFactory
  2. FactoryBeanisSingleton() 返回 false 会怎样?

    • 每次 getBean() 都会调用一次 getObject(),创建一个新对象。Spring 不会缓存它,适合创建非单例的复杂对象(比如原型作用域的连接对象)。
  3. 为什么要用 FactoryBean 而不是 @Bean 方法?

    • 简单场景用 @Bean 就够了。但如果创建逻辑需要框架级别的抽象(比如 MyBatis、Feign 这种需要大量配置的场景),FactoryBean 更合适,因为它是一个独立的组件,可以被其他机制(如 BeanPostProcessor)感知和处理。另外 FactoryBean 支持泛型,类型推断更精准。

常见面试变体

  • "FactoryBeanBeanFactory 有什么区别?"
  • "Spring 中 FactoryBean 有什么用?你在项目中用过吗?"
  • "MyBatis 是怎么和 Spring 整合的?"(本质就是 SqlSessionFactoryBean
  • "getBean("&xxx") 是什么意思?"

记忆口诀

"BeanFactory 是大工厂,FactoryBean 是小工人;大工厂管所有人,小工人专做复杂活。"

总结

BeanFactory 是 Spring IoC 容器的根基,负责管理所有 Bean 的生命周期;FactoryBean 是一个特殊的 Bean,用来封装复杂对象的创建逻辑。它俩不是 "二选一" 的关系,而是 "管理者" 和 "被管理者" 的关系——FactoryBean 本身就被 BeanFactory 管理,只不过别人拿它的时候,拿到的是它生产的产品,不是它自己。面试中把这个关系说清楚,再把 & 前缀的细节一补充,面试官基本就满意了。