FactoryBean 的构建

警告
本文最后更新于 2020-11-28,文中内容可能已过时。

spring源码系列文章,示例代码的中文注释,均是 copy 自 https://gitee.com/wlizhi/spring-framework

链接中源码是作者从 github 下载,并以自身理解对核心流程及主要节点做了详细的中文注释。


1 FactoryBean 的作用

Spring 中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean 即 FactoryBean。FactoryBean跟普通Bean不同,其返回的对象不是指定类的一个实例,而是该FactoryBean的getObject方法所返回的对象。创建出来的对象是否属于单例由isSingleton中的返回决定。

一般情况下,Spring通过反射机制利用的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean的形式

以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取。

2 FactoryBean 接口的定义

以下是 Spring 中 FactoryBean 接口的定义:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public interface FactoryBean<T> {

	T getObject() throws Exception;

	Class<?> getObjectType();

	default boolean isSingleton() {
		return true;
	}
}

3 应用场景

FactoryBean 通常是用来创建比较复杂的 bean,一般的 bean 直接用 xml 配置即可,但如果一个 bean 的创建过程中涉及到很多其他的 bean 和复杂的逻辑,用 xml 配置比较困难,这时可以考虑用 FactoryBean。

很多开源项目在集成 Spring 时都使用到 FactoryBean,比如 MyBatis3 提供 mybatis-spring 项目中的 org.mybatis.spring.SqlSessionFactoryBean:

1
2
3
4
5
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <!-- 自动扫描mapping.xml文件 -->
    <property name="mapperLocations" value="classpath:mapper/*.xml"></property>
    </bean>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
// ...
public SqlSessionFactory getObject() throws Exception {
    if (this.sqlSessionFactory == null) {
        this.afterPropertiesSet();
    }
    return this.sqlSessionFactory;
}
// ...
}

4 源码分析

4.1 初次创建

AbstractBeanFactory 通过 getBean 向 IOC 容器获取被管理的 Bean。

AbstractBeanFactory.getBean() -> doGetBean()。

来到 doGetBean(),看 bean 第一次创建实例后,调用的地方:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    if (mbd.isSingleton()) {
        sharedInstance = getSingleton(beanName, () -> {
            try {
                //创建Bean实例
                return createBean(beanName, mbd, args);
            } catch (BeansException ex) {
                // Explicitly remove instance from singleton cache: It might have been put there
                // eagerly by the creation process, to allow for circular reference resolution.
                // Also remove any beans that received a temporary reference to the bean.
                destroySingleton(beanName);
                throw ex;
            }
        });
        /*
        TODO 重要程度 5
            如果bean不是FactoryBean类型或者beanName以&开头,则直接返回。
            否则调用FactoryBean的getObject(),且将返回的bean替换为getObject()的返回值。
            FactoryBean接口很重要,具体应用场景见FactoryBean接口注释。
         */
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
}

可以看到,在 getSingleton() 之后,又调用了 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd),给 bean 重新赋值,这里bean的实例就可能被改变了。

如果当前创建的 bean 是 FactoryBean 类型的,调用 getObjectForBeanInstance() 时,最终会返回 FactoryBean.getObject() 返回的对象,也就是最终 getBean() 返回的是这个 getObject() 获取到的实例。

以下是 getObjectForBeanInstance() 的源码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
    protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
        String currentlyCreatedBean = this.currentlyCreatedBean.get();
        if (currentlyCreatedBean != null) {
            registerDependentBean(beanName, currentlyCreatedBean);
        }
        // 从父类方法中获取
        return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);
    }
}

这里调用到了父类的方法,继续看父类的方法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
		// ...

		// 如果bean不是FactoryBean类型或者beanName以&开头,则直接返回。
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		Object object = null;
		// 如果BeanDefinition为null,从缓存中获取,doGetBean() 中传入的就是null
		// createBean后进入这里的话,传入的就不是null
		if (mbd == null) {
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			// 调用FactoryBean的getObject方法
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}
}

上面代码的尾部,调用到了 object = getObjectFromFactoryBean(factory, beanName, !synthetic),这个方法中调用了 getObject()。

源码如下(关键点 - 注意源码中高亮部分):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {

    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) {
					// 调用 factory.getObject();
					object = doGetObjectFromFactoryBean(factory, beanName);
					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 {
								// 这里调用了BeanPostProcessor的后置处理
								object = postProcessObjectFromFactoryBean(object, beanName);
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
							finally {
								afterSingletonCreation(beanName);
							}
						}
						// 加入到缓存,缓存位置:BeanFactory的 factoryBeanObjectCache 成员中
						if (containsSingleton(beanName)) {
							this.factoryBeanObjectCache.put(beanName, object);
						}
					}
				}
				return object;
			}
		}
		// ...
	}
}

doGetObjectFromFactoryBean() 中,调用到了 getObject(),进入 doGetObjectFromFactoryBean()。 源码中关键代码是这么写的:

1
2
3
4
5
6
7
    private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) throws BeanCreationException {
        // ...
        // 调用FactoryBean的 getObject(),这个方法是实现FactoryBean的类中定义的。
        object = factory.getObject();
        // ...
	    return object;
	}

由此可以看出,在实例化流程 doGetBean() -> getSingleton() -> getObjectForBeanInstance() 中,创建完 bean 实例后,返回的并不一定是 bean 实例本身,如果这个 bean 实现了 FactoryBean 接口,那么最终会返回 getObject() 方法生成的对象,这个对象的创建是实现类自定义的。

技巧

如果一个对象的创建十分复杂,需要设置很多参数、初始化等操作。那么我们可以创建一个FactoryBean实现,专门负责构建这个对象,构建的行为就定义在 getObject() 中。

我们把这个自定义的 FactoryBean 加入到 ioc 容器(在类上添加 @Component 注解等方式),当调用 getBean() 实例化时,最终返回的并非这个 FactoryBean 实现类对象,而是 getObject() 中构建的对象。

4.2 缓存中获取

从上面的代码分析中已经知道,最终调用了 getObject() 之后,会将这个实例缓存到一个变量中,这个变量是 factoryBeanObjectCache

回到 doGetBean() 中开始的代码块,先从缓存中获取实例,如果获取到了,同样会调用 getObjectForBeanInstance(),判断实例是否是 FactoryBean 类型。

源码如下:

1
2
3
4
5
6
7
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        // ...
        // 如果bean不是FactoryBean类型或者beanName以&开头,则直接返回。
        // 否则将bean强转为FactoryBean类型,并调用getObject()方法返回。
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
在 [06 循环依赖的实现原理 - getSingleton()] 中有提到,这里可能返回一个bean实例。实际上在 bean 第一次创建后,后面再获取都是从缓存中拿的。拿到了之后,经过一些处理,就返回。这个处理就是判断 FactoryBean 的处理。

从上面源码中可以看到,如果从缓存中获取到,会调用 getObjectForBeanInstance() 。很明显,在第一次创建 bean 实例时,就调用过这个方法,会把创建的结果缓存到 factoryBeanObjectCache 变量中,这里就直接从 factoryBeanObjectCache 变量中获取的实例。

最终,如果这个 bean 是 FactoryBean 类型,会被替换掉。

4.3 获取原始bean

关于获取原始bean的方式,在 beanName 前加一个前缀 &,就可以获取到原始 bean 实例。

在 getObjectForBeanInstance() 中有这么一段源码:

1
2
3
4
5
6
7
8
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
        // 如果bean不是FactoryBean类型或者beanName以&开头,则直接返回。
        if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
            return beanInstance;
        }
    }
}

看一下 isFactoryDereference() 的源码:

1
2
3
4
5
public abstract class BeanFactoryUtils {
    public static boolean isFactoryDereference(@Nullable String name) {
		return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
	}
}

可以看到,如果 beanName以 BeanFactory.FACTORY_BEAN_PREFIX 开头,就会返回true。

BeanFactory.FACTORY_BEAN_PREFIX 常量的声明:

1
2
3
public interface BeanFactory {
	String FACTORY_BEAN_PREFIX = "&";
}

结合上面的源码,如果 getBean() 时,传入的 beanName 是以 & 开头,走到 getObjectForBeanInstance() 时,就不会执行 FactoryBean 的逻辑,而是直接返回 bean 实例。