FactoryBean vs BeanFactory

候选人小韩在面试字节 P6 时,面试官问道:

"FactoryBean 和 BeanFactory 有什么区别?"

小韩说:"FactoryBean 是用来创建 Bean 的..."

面试官追问:"那 BeanFactory 呢?"

小韩说:"BeanFactory 也是...呃...不太一样..."

面试官继续追问:"MyBatis 整合 Spring 时用的是什么?"

小韩答不上来。

【面试官心理】 这道题我用来测试候选人对 Spring 容器体系的理解深度。FactoryBean 和 BeanFactory 只差一个字,但完全是两个东西。能说清楚区别的占 30%,能说出 MyBatis 用的什么的占 10%。能答到最后的,基本都看过 Spring 源码。


一、核心问题 🔴

1.1 问题拆解

第一层:概念

  • "FactoryBean 和 BeanFactory 有什么区别?"
  • "FactoryBean 是 Bean 吗?"

第二层:用途

  • "FactoryBean 用来做什么?"
  • "Spring 内部哪些地方用到了 FactoryBean?"

第三层:源码

  • "FactoryBean 的 getObject() 什么时候被调用?"
  • "FactoryBean 和 @Bean 有什么关系?"

第四层:实战

  • "MyBatis 整合 Spring 用的是什么?"
  • "什么场景下需要自定义 FactoryBean?"

1.2 ❌ 错误示范

候选人原话 A:"FactoryBean 和 BeanFactory 都是 Spring 的容器,用来创建 Bean 的。"

问题诊断

  • 完全混淆了两个概念
  • BeanFactory 是容器,FactoryBean 是特殊的 Bean
  • 说明基础知识不扎实

候选人原话 B:"FactoryBean 是一个接口,实现它可以自定义 Bean 的创建过程。"

问题诊断

  • 知道 FactoryBean 是接口,但说不清它和普通 Bean 的区别
  • 不知道 FactoryBean 本身也是一个 Bean

候选人原话 C:"FactoryBean 和 @Bean 是一样的,都是创建 Bean。"

问题诊断

  • 混淆了 FactoryBean 和 @Bean 注解
  • @Bean 是注解,FactoryBean 是接口

1.3 标准回答

P5 回答:核心区别

这是两个完全不同的东西:

对比BeanFactoryFactoryBean
角色Spring IoC 容器的顶层接口容器中的一种特殊 Bean
作用管理所有 Bean 的生命周期用来创建复杂的 Bean
接口方法getBean() 等容器方法getObject() 等创建方法
子接口ApplicationContext 继承它无子接口
使用场景不直接使用自定义 Bean 创建逻辑
// BeanFactory - Spring IoC 容器的接口
public interface BeanFactory {
    Object getBean(String name);
    <T> T getBean(Class<T> requiredType);
    <T> T getBean(String name, Class<T> requiredType);
    boolean containsBean(String name);
    // ... 其他容器方法
}

// FactoryBean - 特殊的 Bean,用于创建 Bean
public interface FactoryBean<T> {
    // 返回创建的对象
    T getObject();

    // 返回创建的对象类型
    Class<?> getObjectType();

    // 是否单例
    default boolean isSingleton() {
        return true;
    }
}

1.4 追问升级

追问 1:FactoryBean 是怎么工作的?

这是理解 FactoryBean 的核心:

// FactoryBean 本身也是一个 Bean
// 但它的作用是"生产"其他 Bean

@Service
public class MyFactoryBean implements FactoryBean<MyObject> {
    @Override
    public MyObject getObject() {
        // 这个方法返回的对象会被注册到容器中
        // 而不是 MyFactoryBean 本身
        return new MyObject();
    }

    @Override
    public Class<?> getObjectType() {
        return MyObject.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

当调用 context.getBean("myFactoryBean") 时:

  • 如果 Bean 名字以 & 开头,返回 FactoryBean 本身
  • 否则返回 getObject() 返回的对象
ApplicationContext context = ...;

// 获取 getObject() 返回的对象
MyObject obj = context.getBean("myFactoryBean"); // 返回 MyObject

// 获取 FactoryBean 本身
FactoryBean<?> factory = context.getBean("&myFactoryBean"); // 返回 MyFactoryBean

源码实现:

// AbstractBeanFactory.getBean()
protected <T> T doGetBean(String name, Class<T> requiredType, Object[] args, boolean typeCheckOnly) {
    Object bean = getSingleton(beanName);

    if (bean == null) {
        bean = createBean(beanName, mbd, args);
    }

    // 【关键】如果是 FactoryBean,获取其产品
    if (bean instanceof FactoryBean) {
        FactoryBean<?> factory = (FactoryBean<?>) bean;
        boolean isEagerInit = (beanName.startsWith("&") || factory.isSingleton());

        if (isEagerInit) {
            // 调用 getObject() 获取实际对象
            bean = factory.getObject();
        }
    }

    return (T) bean;
}

追问 2:Spring 内部哪些地方用到了 FactoryBean?

这是面试高频追问:

使用场景FactoryBean说明
MyBatisMapperFactoryBean为每个 Mapper 接口创建代理对象
Spring JDBCJdbcBeanDefinitionReader创建数据源相关 Bean
Spring ORMLocalSessionFactoryBean创建 Hibernate SessionFactory
AOPProxyFactoryBean创建 AOP 代理
事务TransactionAwareProxyFactory创建事务代理

MyBatis 整合 Spring

// MyBatis-Spring 中的核心类
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {

    private Class<T> mapperInterface;

    @Override
    public T getObject() {
        // 【关键】创建 Mapper 代理对象
        return getSqlSession().getMapper(mapperInterface);
    }

    @Override
    public Class<T> getObjectType() {
        return mapperInterface;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

// 使用方式
@Bean
public MapperFactoryBean<UserMapper> userMapper() {
    MapperFactoryBean<UserMapper> factory = new MapperFactoryBean<>();
    factory.setMapperInterface(UserMapper.class);
    factory.setSqlSessionFactory(sqlSessionFactory);
    return factory;
}

Spring 自己的 ProxyFactoryBean

// ProxyFactoryBean 是 Spring AOP 的核心类
public class ProxyFactoryBean implements FactoryBean<Object>, AopProxyFactory {

    @Override
    public Object getObject() {
        // 创建 AOP 代理对象
        return createAopProxy().getProxy();
    }

    @Override
    public Class<?> getObjectType() {
        return targetClass;
    }
}

// 使用示例
@Bean
public ProxyFactoryBean<UserService> userServiceProxy() {
    ProxyFactoryBean<UserService> factory = new ProxyFactoryBean<>();
    factory.setTarget(targetUserService);
    factory.addAdvisor(transactionAdvisor);
    factory.addAdvice(loggingInterceptor);
    return factory;
}

追问 3:FactoryBean vs @Bean

// FactoryBean 方式
@Service
public class MyFactoryBean implements FactoryBean<MyObject> {
    @Override
    public MyObject getObject() {
        // 复杂的创建逻辑
        MyObject obj = new MyObject();
        obj.setProperty("value");
        return obj;
    }
}

// @Bean 方式
@Configuration
public class MyConfig {
    @Bean
    public MyObject myObject() {
        MyObject obj = new MyObject();
        obj.setProperty("value");
        return obj;
    }
}
对比FactoryBean@Bean
声明方式实现接口使用注解
灵活性高,可控制 isSingleton一般
生命周期支持完整 Bean 生命周期配置类中
注入能力可以注入依赖可以注入依赖
适用场景需要细粒度控制 Bean 创建大多数场景

什么时候用 FactoryBean:

  1. 创建的 Bean 类型在编译时未知(如泛型)
  2. 需要在 Bean 创建前后做一些额外处理
  3. 整合第三方库时(如 MyBatis)
  4. 需要创建代理对象时(如 AOP)

二、延伸问题 🟡

2.1 自定义 FactoryBean 示例

场景:创建带配置的第三方客户端

// 第三方客户端
public class ThirdPartyClient {
    public ThirdPartyClient(String apiKey, String baseUrl) { }
}

// 自定义 FactoryBean
@Component
public class ThirdPartyClientFactoryBean implements FactoryBean<ThirdPartyClient> {

    @Value("${thirdparty.api-key}")
    private String apiKey;

    @Value("${thirdparty.base-url}")
    private String baseUrl;

    @Override
    public ThirdPartyClient getObject() {
        // 创建客户端实例
        return new ThirdPartyClient(apiKey, baseUrl);
    }

    @Override
    public Class<?> getObjectType() {
        return ThirdPartyClient.class;
    }

    @Override
    public boolean isSingleton() {
        return true; // 单例
    }
}

// 使用
@Autowired
private ThirdPartyClient client; // 直接使用,不需要知道 FactoryBean

2.2 ObjectFactory 和 FactoryBean

// ObjectFactory - 只是 getObject() 接口
@FunctionalInterface
public interface ObjectFactory<T> {
    T getObject();
}

// FactoryBean - 增强版,有类型信息和单例标识
public interface FactoryBean<T> {
    T getObject();
    Class<?> getObjectType();
    default boolean isSingleton();
}

// ObjectFactory 的使用场景
@Service
public class MyService {
    @Autowired
    private ObjectFactory<MyObject> myObjectFactory;

    public void useObject() {
        // 每次调用 getObject() 都创建新对象
        MyObject obj = myObjectFactory.getObject();
    }
}

三、生产避坑

3.1 FactoryBean 的名字问题

// 如果 FactoryBean 的 Bean 名字是 userDao
// 通过 getBean("userDao") 获取的是 getObject() 返回的对象
// 通过 getBean("&userDao") 获取的是 FactoryBean 本身

@Autowired
private UserDao userDao; // 注入的是 getObject() 返回的类型

// 如果需要注入 FactoryBean 本身
@Autowired
private FactoryBean<UserDao> userDaoFactory;

3.2 isSingleton 的影响

@Component
public class MyFactoryBean implements FactoryBean<MyObject> {

    @Override
    public MyObject getObject() {
        // 每次调用都创建新对象
        return new MyObject();
    }

    @Override
    public boolean isSingleton() {
        return false; // 返回 false
    }
}

// 行为:
context.getBean("myFactoryBean"); // 每次调用 getObject()
context.getBean("myFactoryBean"); // 每次调用 getObject()

四、工程选型

4.1 选择建议

场景推荐方式原因
普通 Bean 创建@Bean简单直观
泛型 BeanFactoryBean泛型在接口层面处理
第三方库整合FactoryBean无法使用 @Bean
需要在创建时注入FactoryBean 或 @Bean都可以
动态决定类型FactoryBean可以根据参数决定

五、面试总结

FactoryBean vs BeanFactory,虽然名字很像,但完全不是一回事。

P5 候选人能说出"BeanFactory 是容器,FactoryBean 是特殊的 Bean"。 P6 候选人能说清 FactoryBean 的工作原理,能说出 MyBatis 用的是 MapperFactoryBean。 P7 候选人能说出 ProxyFactoryBean 的作用,能给出自定义 FactoryBean 的场景。

记住:

  • BeanFactory = 容器
  • FactoryBean = 工厂 Bean
  • & = 获取工厂本身