一、FactoryBean
FactoryBean
是Spring
框架提供的一个核心接口之一,用来创建复杂或无法通过默认构造函数创建的对象。这种情况下通过实现FactoryBean
接口,可以自定义实例化Bean
的过程,包括Bean
的对象类型、初始化、销毁等。
在应用场景中,可以使用 FactoryBean
集成第三方框架、开源库或是处理一些特殊的业务需求,将Bean
的控制权交由我们灵活控制。
比如:通过FactoryBean
将创建对象的逻辑封装起来,而对于使用者则无感知,正常向 IOC
容器获取 Bean
即可。
如果想要获取 FactoryBean
自身的话,则可以在 beanName
前面加个 &
符号,这点我们会在后面的源码分析中体验出来。
下面是 FactoryBean
的组成:
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
对应三个核心方法的说明:
isSingleton()
: 获取由FactoryBean
创建的Bean
实例是单例还是原型,默认为单例。T getObject()
: 获取由FactoryBean
创建的Bean
实例,如果isSingleton
的作用域为单例,会将该实例进行缓存。Class<?> getObjectType()
: 获取由FactoryBean
要创建Bean
的类型。
下面简单体验下 FactoryBean
的使用:
@Component
public class FactoryBeanTest implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new TestABC();
}
@Override
public Class<?> getObjectType() {
return TestABC.class;
}
@Override
public boolean isSingleton() {
return true;
}
/**
* 实际Bean
*/
public static class TestABC{
}
}
测试:
public class App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext("com.example.demo.bean");
System.out.println(context.getBean("factoryBeanTest"));
System.out.println(context.getBean("&factoryBeanTest"));
}
}
可以看出如果以 &
符号开头则获取的是 FactoryBean
自身。
下面从源码的角度分析下,context.getBean
获取 Bean
的过程中是如何处理 FactoryBean
的。
二、源码解读
在本专栏的前面文章中有针对 Bean
创建过程进行源码分析,如果了解的应该知道实际 Bean
创建的逻辑在 AbstractBeanFactory
的 doGetBean
方法中,这里也是从 doGetBean
方法入手,如果对 Bean
创建过程不了解也可以参考下面这篇文章:
Spring 源码解析 - Bean创建过程 以及 解决循环依赖
在 doGetBean
方法中,首先会去单例池中查找是否存在,如果存在这里会使用 getObjectForBeanInstance
获取到最终的 Bean
实例:
如果此时单例池中没有的话,进行下面 Bean
实例初始化的过程,当实例化完成后同样也使用 getObjectForBeanInstance
获取到最终的 Bean
实例
这个方法看似不起眼,其实对于FactoryBean
起着关键的作用,下面就主要看下 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.
// 当前bean的名称是否是工厂模式, 主要判断名称是否以 & 开头,如果是以 & 开头,说明当前获取的是 FactoryBean 本身
if (BeanFactoryUtils.isFactoryDereference(name)) {
// 如果是 NullBean 直接返回
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 如果不是 FactoryBean 的话则抛出异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
// 返回 FactoryBean 自身
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.
// 当前的 bean实例不是 FactoryBean,则直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
// 是 FactoryBean 的情况下
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 从缓存中获取
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 转为 FactoryBean 类型
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());
// 获取 FactoryBean 实际的 Bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
在该方法中,首先第一步对 name
进行判断,如果是以 &
开头,说明当前获取的是 FactoryBean
本身,如果此时 Bean
不是 NullBean
也不是 FactoryBean
则只有报错了。
下面如果不是 FactoryBean
类型,直接返回当前实例即可。
再下面逻辑肯定是 FactoryBean
类型了,如果缓存中不存在话则最终调用了 getObjectFromFactoryBean
方法来获取 Bean
,下面看到该方法中:
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 如果 FactoryBean 里的 Bean 是单例模型, 并且单例池中存在
if (factory.isSingleton() && containsSingleton(beanName)) {
// 对单例池加锁
synchronized (getSingletonMutex()) {
//尝试从缓冲中获取Bean
Object object = this.factoryBeanObjectCache.get(beanName);
// 如果缓存中不存在
if (object == null) {
// 从 FactoryBean 中的 getObject() 获取 Bean
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) {
// 如果缓存存在使用缓存中的Bean
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);
}
}
}
// 返回实际的 Bean
return object;
}
} else {
// 如果不是单例模式 或 单例池中不存在
// 从 FactoryBean 中获取 Bean
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);
}
}
// 返回实际的 Bean
return object;
}
}
这里有两个分支,FactoryBean
中的 Bean
是单例还是不是单例,也就是 isSingleton
方法是 true
还是 false
,如果是单例的话,则尝试通过 factoryBeanObjectCache
获取缓存对象,从这里就可以看出 FactoryBean
中的 Bean
的单例缓存是存在了 factoryBeanObjectCache
中,而不是 Spring
的单例池。
在该方法中实际获取 Bean
是通过 doGetObjectFromFactoryBean
方法,如果单例模式则将 Bean
放入 factoryBeanObjectCache
中缓存,如果不是单例,则直接返回获取到的 Bean
,下面看到 doGetObjectFromFactoryBean
方法中:
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 {
// 调用 FactoryBean 中的 getObject 获取实际 Bean。
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
方法获取到最终的 Bean
实例。