1.了解Spring
中对于FactoryBean
接口设计和使用
首先我们来看FactoryBean
的源码:
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
然后看它的一个子接口SmartFactoryBean
public interface SmartFactoryBean<T> extends FactoryBean<T> {
default boolean isPrototype() {
return false;
}
default boolean isEagerInit() {
return false;
}
}
FactoryBean
的作用是什么?从FactoryBean
这个类的名字我们可以知道其实是一个Factory
的Bean
,也就是一个工厂Bean
,既然是工厂Bean,肯定是用来造Bean的对吧!不错FactoryBean
的作用就是给容器中导入组件。
对它的方法进行简单的介绍(既然SmartFactoryBean
是FactoryBean
的扩展,下面也一起讲解):
- 1.
getObject
方法就是用来导入组件的,你可以在这里new
一个对象并进行相关的配置,然后return
就行了。 - 2.
getObjectType
方法很明显嘛,就是你要导入的组件的类型,泛型T
也就是你要导入的组件的类型。 - 3.
isSingleton
方法用来决定这个Bean
是否是单例的,isPrototype
同理。 - 4.
isEagerInit
方法决定即将导入这个Bean
是否是懒加载的,如果return true
,那么在Spring IOC
容器启动的过程中就会将getObject
导入的Bean
进行实例化和初始化,如果return false
,只要当你显式进行getBean
时才会对导入的Bean
进行实例化和初始化。
下面来看一个简单的FactoryBean
的使用
@Component
public class MyFactoryBean implements SmartFactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public boolean isEagerInit() {
return true;
}
}
我们通过上面的简单代码就可以为容器中导入一个FactoryBean
对象,而在FactoryBean
中我们又给导入了一个User
对象,因为我们配置了isEagerInit
中return true
,因此在IOC
容器启动的过程中就把user
对象完成了实例化和初始化工作。为了方便进行说明,我们把myFactoryBean
这个对象称作FactoryBean
,把user
这个对象成为FactoryBeanObject
。
2. 了解FactoryBean
在Spring
源码当中的实现?
2.1 在源码当中去找到在哪去创建FactoryBean
和FactoryBeanObject
?
首先我们知道Spring IOC
容器启动的核心流程都在AbstractApplicationContext
的refresh
方法中被定义了,因此我们无论看Spring
的哪一块代码,都可以从refresh
方法作为入口点。
首先我们找到实例化所有的单实例Bean的方法finishBeanFactoryInitialization
,这个方法的最后一步是beanFactory.preInstantiateSingletons();
,我们主要关注的就是这里的代码,这个方法的实现在它的子类DefaultListableBeanFactory
当中。
2.2 看看FactoryBean
是如何导入FactoryBeanObject
的?
我们从上面的图当中可以很清楚的看到,这里FactoryBean
和非FactoryBean
就走到了不同的逻辑。
- 1.如果是非
FactoryBean
,直接就getBean
去创建Bean
了。 - 2.如果是
FactoryBean
,那么就把beanName
加上前缀FACTORY_BEAN_PREFIX
(也就是&
),然后调用getBean
从容器中获取/创建对象,比如上面我导入的myFactoryBean
组件,这里getBean
就会使用&getFactoryBean
作为beanName
。
但是我们容器中真的有&getFactoryBean
这个beanName
的Bean
吗?很显然没有,我们来看getBean
方法的逻辑。真正的逻辑在AbstractBeanFactory.doGetBean
当中。
2.2.1 通过getBean
获取FactoryBean
image.png
首先,进来第一步是transformedBeanName
,它做了什么呢?
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
我们可以看到:
- 1.如果
name
不是以&
开头的,那么根本就不会进行转换,直接return
。 - 2.如果名字是以
&
开头呢,就把名字前面的所有的&
都去掉。
我们这里就明白了,transfromedBeanName
其实就是把名字做一个转换,如果名字前有&
的都给去掉,比如我们之前的&myFactoryBean
就在这里变成了myFactoryBean
。
接着第二步
Object sharedInstance = getSingleton(beanName);
就是从三级缓存中拿对象(也就是我们背的八股文的循环依赖的解决方案的三级缓存)。但是我们这里根本就没有创建过myFactoryBean
这个对象,从三级缓存中肯定是拿不到的,就要走后续的逻辑去创建myFactoryBean
对象,创建的过程我们暂时不管,忽略掉。
2.2.2 FactoryBeanObject
的创建
image.png
然后就是判断,这个Bean
是否是SmartFactoryBean
,如果是的话,还要考虑是否isEagerInit
,这个我们在之前已经讲述过,我们这里配置了true
,因此这里会去执行getBean
,传入的beanName
是myFactoryBean
。
是不是很奇怪?按照我们刚刚的逻辑,已经创建了myFactoryBean
这个对象了,而且还保存到bean
对象当中了。这里还调用getBean
干嘛,不是白干活吗?我们继续看doGetBean
的逻辑。
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
因为我们之前已经创建过了myFactoryBean
对象,因此getSingleton
就可以从三级缓存当中去拿到对象myFactoryBean
,因此sharedInstance
就拿到非空,就走到getObjectForBeanInstance
这个方法当中去了,而FactoryBeanObject
(user
)的创建,就是在这个方法中去进行创建的,这也就是为什么我们要两次调用getBean
的原因,因为在这里会触发不同的逻辑。
我们下面就来看getObjectForBeanInstance
方法的逻辑
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
下面,我们进行挨个步骤的拆解分析
(1) getObjectFromFactoryBean
步骤1-判断你调用getBean
时传递的参数是否以&
作为前缀
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
这个部分的目的是为了什么?它其实就是判断,name
是否是以&
开头的,如果是的话,直接return beanInstance
,也就是直接return FactoryBean
。如果name
不是以&
开头的,那么不会进入这里,直接进入后续的逻辑。(需要注意的是:这里传递的参数beanName
一定是去掉了&
的,而name
是没有去掉&
的原生beanName
)
(2) getObjectFromFactoryBean
步骤2-判断getSingleton
拿到的对象是否是FactoryBean
接着是下面这段代码
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
因为getSingleton
返回非空的情况,都会进入这里,因此beanInstance
有可能是一个FactoryBean
,也可能就是一个普通的Bean
,因此这里需要过滤掉所有的普通的Bean
。
(3) getObjectFromFactoryBean
步骤3-尝试从缓存当中去获取FactoryBeanObject
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
object = getCachedObjectForFactoryBean(beanName);
}
这里传递的mbd
为null
,因此走else
逻辑,而这个else
中调用的方法的意图,从名字上我们就很清晰的看到,是从缓存中根据FactoryBean
的beanName
去拿到它导入的FactoryBeanObject
。(具体代码为return this.factoryBeanObjectCache.get(beanName);
)
如果第一次来,这里很显然为拿不到,因此会走下面的逻辑;而如果已经创建过了,第二次来这里,直接就从缓存当中拿出来对象了。
(4) getObjectFromFactoryBean
步骤4-创建FactoryBeanObject
并加入到缓存当中
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
这里意图很清晰嘛,就是调用getObjectFromFactoryBean
去完成FactoryBeanObject
对象的创建,具体的逻辑如下。
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
我们可以看到这里的逻辑就是:
- 1.如果是
FactoryBeanObject
是单例的,那么就加上锁,然后从缓存中拿对象,如果拿到了,那么就return
,如果拿不到,就去调用FactoryBean.getObject
方法去创建一个,然后再放入缓存当中。 - 2.如果
FactoryBean
不是单例的?那么直接新创建一个并return
就行了。
我们还要来看看doGetObjectFromFactoryBean
中是如何创建FactoryBeanObject
的?
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
其实很简单,就是简单调用了一下FactoryBean.getObject
方法罢了。
(5) getObjectFromFactoryBean
步骤5-对FactoryBeanObject
的后置处理工作(postProcessObjectFromFactoryBean
)
在创建完FactoryBeanObject
之后,我们的Bean
只是完成了实例化,并未完成初始化工作,比如有些特定的Bean
需要完成动态代理,就会在这里进行回调。
postProcessObjectFromFactoryBean
在子类当中的实现如下:
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
接着往下看
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
我们可以看到,它是遍历所有的BeanPostProcessor
,执行它的postProcessAfterInitialization
方法,也就是说BeanPostProcessor
有机会在这里对FactoryBeanObject
去完成动态代理,我们知道Spring AOP
用到的BeanPostProcessor
实现动态代理的逻辑,其实就是在postProcessAfterInitialization
方法当中!
3. FactoryBean
的更多知识
3.1 我们如何拿到FactoryBean
和FactoryBeanObject
?
我们通过上面的源码分析可以知道:
- 1.如果你在
getBean
时使用了&
作为前缀(比如&myFactoryBean
),那么在getSingleton
拿到了FactoryBean
之后,就会因为&
前缀,导致不会从缓存当中去获取FactoryBeanObject
,因此拿到的就是FactoryBean
对象本身(比如myFactoryBean
)。 - 2.如果你在
getBean
时没加前缀&
(比如myFactoryBean
),那么在getSingleton
之后,就会因为拿到的这个对象是FactoryBean
,就会直接从缓存中拿到FactoryBean
导入的FactoryBeanObject
对象(如果是懒加载的话,在第一次获取时,会先进行创建)。 - 3.那么
IOC
容器(三级缓存)中究竟有没有user
作为beanName
的Bean
,我们可以从源码当中可以看到,创建和导入User
对象时,都没有使用到user
,都使用到的FactoryBean
本身的beanName
,因此很显然缓存当中并没有user
作为beanName
的对象,你通过user
去getBean
肯定是获取不到的。
我们有很多种方式可以获取到FactoryBean
/FactoryBeanObject
直接注入ApplicationContext
/BeanFactory
(或者实现相应的XXXAware
接口),然后通过ApplicationContext
/BeanFactory
去调用getBean
获取
@Autowired
ApplicationContext applicationContext;
@Autowired
BeanFactory beanFactory;
然后使用beanFactory.getBean("myFactoryBean")
可以获取到我们创建的User
对象,使用beanFactory.getBean("&myFactoryBean")
可以获取到我们创建的FactoryBean
对象本身,也就是myFactoryBean
这个对象。
当然,也可以直接@Qualifier
直接进行注入
@Autowired
@Qualifier("myFactoryBean")
User user;
3.2 FactoryBean
的应用?
在MyBatis
中去导入SqlSessionFactory
这个核心组件时,就使用到了SqlSessionFactoryBean
,而这个对象就是FactoryBean
,当然其实MyBatis
中的MapperFactoryBean
也是使用的FactoryBean
。其实整个MyBatis
就是通过Spring
的FactoryBean
机制为容器中导入Bean
,从而实现相关的功能的。
网友评论