BeanFactory 和 FactroyBean 的关系?


面试考察点

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

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

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

核心答案

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

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

一句话总结: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-SpringSqlSessionFactoryBeanSqlSessionFactory
Spring-Cloud-OpenFeignFeignClientFactoryBeanFeign 代理对象
Spring 事务TransactionProxyFactoryBean事务代理对象
Spring AOPProxyFactoryBeanAOP 代理对象

你看,这些框架里的核心对象,创建过程都很复杂,全部交给 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 管理,只不过别人拿它的时候,拿到的是它生产的产品,不是它自己。面试中把这个关系说清楚,再把 & 前缀的细节一补充,面试官基本就满意了。