BeanFactory 和 FactoryBean 的关系?

#Java#面试八股

BeanFactory 和 FactoryBean 的关系?

结论先行:名字颠倒,职责完全不同。BeanFactory 是容器本身——IoC 的顶层接口,负责"管理 Bean"(getBean、作用域、生命周期);FactoryBean 是容器里的一个 Bean——负责"生产 Bean",当某个对象构造过程复杂或需要代理时,把构造逻辑写进 getObject()。二者是"仓库"与"仓库里的制造机"的关系,不是继承也不是别名。

一、本质对比

维度BeanFactoryFactoryBean
身份容器接口(org.springframework.beans.factory.BeanFactory)普通 Bean,实现 FactoryBean<T> 接口
职责管理 Bean 定义、创建、注入、作用域生产某个复杂对象
关键方法getBean、getBeanProvider、containsBeangetObject()、getObjectType()、isSingleton()
实现类举例DefaultListableBeanFactorySqlSessionFactoryBean、MapperFactoryBean、RpcProxyFactoryBean
数量一个应用通常一个容器里可以有任意多个
谁调用谁容器调用 FactoryBean 的 getObject()被容器管理,产出物交给容器

二、& 前缀:一个名字两个对象

容器中 Bean 名 "userMapper":
   getBean("userMapper")   → FactoryBean#getObject() 的返回值(UserMapper 代理)
   getBean("&userMapper")  → FactoryBean 实例本身(MapperFactoryBean)

推理过程:
  BeanFactory#getBean 先查 singletonObjects
    → 命中且是 FactoryBean → 返回 getObject()
    → 名字以 & 开头 → 去掉 & 后返回 FactoryBean 本身

三、自定义 FactoryBean

public class RpcProxyFactoryBean<T> implements FactoryBean<T>, BeanFactoryAware {

    private Class<T> interfaceClass;
    private String serviceUrl;
    private BeanFactory beanFactory;

    @Override
    @SuppressWarnings("unchecked")
    public T getObject() {
        // 复杂构造:生成动态代理,把远程调用伪装成本地接口
        return (T) Proxy.newProxyInstance(
                interfaceClass.getClassLoader(),
                new Class<?>[]{interfaceClass},
                (proxy, method, args) -> invokeRemote(serviceUrl, method, args));
    }

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

    @Override
    public boolean isSingleton() {
        return true;      // 单例则 getObject 只调用一次,结果被缓存
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    public void setInterfaceClass(Class<T> c) { this.interfaceClass = c; }
    public void setServiceUrl(String url) { this.serviceUrl = url; }
}
@Configuration
public class RpcConfig {
    @Bean
    public RpcProxyFactoryBean<UserService> userServiceProxy() {
        RpcProxyFactoryBean<UserService> f = new RpcProxyFactoryBean<>();
        f.setInterfaceClass(UserService.class);
        f.setServiceUrl("http://user-svc");
        return f;
    }
}

四、真实案例:MyBatis 的 Mapper

MyBatis 的 Mapper 只有接口、没有实现类,正是靠 MapperFactoryBean 把接口"变成"可注入的代理:

@MapperScan("com.demo.mapper")
   └─ MapperScannerConfigurer(BeanDefinitionRegistryPostProcessor)
        └─ 为每个接口注册一个 MapperFactoryBean 的 BeanDefinition
             └─ 容器 getBean("userMapper")
                  └─ MapperFactoryBean#getObject() → JDK 动态代理
                       └─ 方法调用被代理拦截,转成 SqlSession 的 SQL 执行

五、常见追问

  • 问:FactoryBean 的 getObject() 什么时候执行? 首次 getBean 或被注入时;isSingleton() 为 true 时会被缓存,为 false 则每次都调用。
  • 问:FactoryBean 和 @Bean 方法有什么区别? @Bean 方法在配置类解析阶段就被调用并注册实例;FactoryBean 注册的是"工厂",真实对象延迟到 getObject()。
  • 问:getObjectType() 返回 null 会怎样? 容器无法提前判断类型,会提前调用 getObject() 来探测,可能带来副作用或提前初始化。
  • 问:BeanFactory 与 ApplicationContext 什么关系? 后者继承前者并增强(事件、国际化、资源、AOP 集成、自动注册 BPP),BeanFactory 是最小契约。
  • 问:能用 FactoryBean 做对象池吗? 勉强可以,但更推荐 @Bean + 池化组件,FactoryBean 适合"创建逻辑与业务无关"的场景。

小结

一句话:BeanFactory 是容器,FactoryBean 是容器里的工厂;前者管所有 Bean,后者只产出自己那一个对象。 记住 & 前缀与 getObject() 的延迟语义,再加 MyBatis Mapper 这个实例,基本就够用了。

笔记加载中…