吊打面试官系列:BeanFactory和FactoryBean的区别
01 引言
面试造火箭,入职拧螺丝。这是候选人的进入职场的切身感受。坦白来讲,日常业务开发中根本没有什么用。但是如果涉及架构、脚手架、开发封装或者源码理解,却是大有用处。
面试的目的不是刁难,而是了解候选人的技术深度和广度。
今天,我们来看一个高频面试题:BeanFactory
和FactoryBean
的区别。
02 考察点
该面试题主要考察了候选人对Spring
源码的理解程度。
BeanFactory
和FactoryBean
是Spring中非常重要的两个接口
。其中FactoryBean
更是对Bean
创建的一个扩展点,独立控制Bean
的创建过程,并由Spring
容器管理。
BeanFactory
和FactoryBean
也非常容易混淆,名称相似但功能完全不同。
03 BeanFactory
BeanFactory
的本质是一个Bean
工厂,是整个Spring
中IOC
容器的一个接口,负责管理Bean
的创建和生命周期。
其中ApplicationContext
又是对BeanFactory
功能的扩展,如增加AOP
、事件等。
3.1 源码分析
先来看看源码中的主要功能:
源码中功能主要是用来获取Bean
对象,判断Bean
对象的属性。
而之前我们演示过Spring
的IOC
容器的一个实现类就是AnnotationConfigApplicationContext
,来看看简单的继承关系:
3.2 案例分析
这是一个非常典型的使用Spring
容器获取Bean
对象的案例。因为ApplicationContext
继承BeanFactory
,并且这里使用了BeanFactory
中的方法,所以这里完全可以使用BeanFactory
接收。
而在实际的业务项目中,我们通常会使用Spring
的扩展接接口ApplicationContextAware
,获取到ApplicationContext
容器,然后再操作容器中的Bean
对象。
@Component
public final class SpringUtil implements ApplicationContextAware, DisposableBean {
/**
* ApplicationContext
*/
private static ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) {
SpringUtil.applicationContext = applicationContext;
}
// ......
}
04 FactoryBean
FactoryBean
同样是一个接口,用来定义一个工厂Bean
,他可以产生某种类型的对象。他生产的Bean
仍然被Spring
容器管理。也就是说通过BeanFactory
的getBean()
获取到的。
当Spring
启动时,发现一个Bean
实现了FactoryBean
接口,Spring
就不会直接返回这个Bean
示例,而是通过FactoryBean#getObject()
来返回对象。
4.1 源码
源码非常简单,就3个方法。分别用来获取Bean
、Bean
类型以及是否单例。
4.2 案例分析
先定义一个UserServiceFactoryBean
专门用来生产userService
。
@Component
public class UserServiceFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new UserService();
}
@Override
public Class<?> getObjectType() {
return UserService.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
在容器中获取userService
对象:
@Test
void test() {
ApplicationContext context = new AnnotationConfigApplicationContext("com.simonking.boot.aop");
UserService contextBean = (UserService)context.getBean("userServiceFactoryBean");
contextBean.test();
}
结果就可以获取到UserService
对象了。
但是会发现一个问题:
UserServiceFactoryBean
上的注解默认的BeanName是userServiceFactoryBean
,而在容器中取BeanName为userServiceFactoryBean
的时候返回的Bean
又是UserService
。
这就是开始说的:FactoryBean
不直接返回Bean
而是通过getObject
返回的
isSingleton
如果设为false会怎样?
从容器中获取两次对象返回的Bean
是不同的内存地址:
那如何获取对象本身呢?
只需要Bean
的名称前加&
即可,且内部的方法不影响对象本身:
05 小结
简单总结一下:
BeanFactory
由Spring
框架实现,负责管理和创建很多Bean
,通常不需要开发者自行实现;而FactoryBean
到底是一个Bean
对象,允许开发者定制化Bean
的创建流程,最终还要被BeanFactory
管理。