面试翻车现场
问:getBean("sqlSessionFactory") 拿到的是什么?答 SqlSessionFactory 的只对了一半;追问「那怎么拿到 SqlSessionFactoryBean 本身」,一大半人卡壳——答案是个反直觉的 & 前缀。这题背后是两个名字只差一个词的接口:BeanFactory 是工厂本体,FactoryBean 是工厂里的一个特殊产品。
BeanFactory:IoC 的本体
BeanFactory 是 Spring 容器的顶层接口:getBean、containsBean、getBeanDefinition 等容器能力全在它身上。平时用的 ApplicationContext 继承自它,最终实现类是 DefaultListableBeanFactory。一句话:BeanFactory 是「造 Bean 的工厂」本身。
FactoryBean:会造 Bean 的 Bean
FactoryBean 是个特殊接口:实现它的类自己也注册为 Bean,但容器里对外暴露的不是它,而是 getObject() 返回的对象。三个方法:getObject() 产出真正的 Bean;getObjectType() 声明产出类型;isSingleton() 声明是否单例:
@Component
public class ExpensiveClientFactoryBean implements FactoryBean<ExpensiveClient> {
@Override
public ExpensiveClient getObject() {
// 复杂构建:加载配置、建立连接、预热……
return new ExpensiveClient(buildConfig(), warmUp());
}
@Override
public Class<?> getObjectType() { return ExpensiveClient.class; }
@Override
public boolean isSingleton() { return true; }
}使用端毫无感知:getBean("expensiveClientFactoryBean") 拿到的直接是 ExpensiveClient。想见工厂本人?加 & 前缀:getBean("&expensiveClientFactoryBean")。一个符号,隔开「产品」与「车间」。
为什么需要它:给第三方框架开门
有些对象的创建复杂到没法用 @Component 声明:MyBatis 的 SqlSessionFactory 要解析全部映射文件;Mapper 接口根本没有实现类——MapperFactoryBean 的 getObject() 运行时生成动态代理(MapperProxy);Feign 的远程客户端要生成代理并接入负载均衡。FactoryBean 的意义:把任何复杂的对象创建逻辑,封装成一个标准 Spring Bean——业务代码只管按类型注入,创建黑盒留给框架自己。这是 Spring 生态各类整合方案的通用接入姿势,MyBatis-Plus、Dubbo、OpenFeign 全在用。
一句话总结
BeanFactory 造所有 Bean;FactoryBean 是「会造 Bean 的 Bean」——它产出的对象才是容器里的正主,& 前缀才能见到它本人。下一篇进入 AOP:JDK 动态代理与 CGLIB,看增强到底是怎么长出来的。
评论 (0)