从源码角度聊聊spring中的FactoryBean

说到spring,相信对于BeanFactory大家肯定都不陌生,百度上随便一搜,99都会说什么字如其意:bean工厂啊,容器,管理bean的。。。对于BeanFactory其实就是这样子的,这里我说的肯定没有别人好,这边就不一一赘述了。今天这边主要来谈谈FactoryBean。

先来看一个颠覆你三观的案例:

@Service
public class FactoryBeanTest implements FactoryBean<TestSingleton> {

    @Override
    public TestSingleton getObject() throws Exception {
        return new TestSingleton();
    }

    @Override
    public Class<?> getObjectType() {
        return TestSingleton.class;
    }
    
     @Override
    public boolean isSingleton() {
        return false;
    }
}

在这里插入图片描述
在这里插入图片描述
我们交给spring管理了一个bean:FactoryBeanTest(beanid:factoryBeanTest ) ,但是我们根据annotationConfigApplicationContext去get这个bean的时候,拿到的却是:TestSingleton
如果我们在beanid前加一个 & ,就可以拿到FactoryBeanTest这个对象了。

细心的哥哥们可能注意到了,我们的FactoryBeanTest 实现了:FactoryBean 接口,那么我们就来分析下,这个FactoryBean 接口,以及spring容器在初始化时,是怎么处理这个接口的。
在这里插入图片描述
这个接口有三个方法:

  //指定创建的具体bean对象的类型
   @Nullable
	Class<?> getObjectType();


    //设置创建的对象是否单例,可以不重写默认是单例的,如果需要设置原型需要重写此方法,返回false
   default boolean isSingleton() {
		return true;
	}

    //创建对象bean 具体创建具体对象是由此getObject()方法来创建并返回的
    @Nullable
	T getObject() throws Exception;

那么问题来了:
1,spring在初始化的时候到底做了什么,将原本是FactoryBeanTest的bean替换成了TestSingleton
2,为什么annotationConfigApplicationContext.getBean("&factoryBeanTest")可以拿到FactoryBeanTest

下面来看看spring容器初始化的时候到底做了什么:
首先看下单例的FactoryBean
在spring容器初始化完成,创建bean实例的时候,方法调用入口如下:

org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
            org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

在这里插入图片描述
可以看到,我们这里有13个beanname,5个是我们自己配置的,另外八个事spring内置的一些bean,我们不做关注,这边直接看
factoryBeanTest。

String FACTORY_BEAN_PREFIX = "&";

if (isFactoryBean(beanName)) {
	Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
	if (bean instanceof FactoryBean) {
		final FactoryBean<?> factory = (FactoryBean<?>) bean;
		boolean isEagerInit;
		if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
			isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
							((SmartFactoryBean<?>) factory)::isEagerInit,
					getAccessControlContext());
		}
		else {
			isEagerInit = (factory instanceof SmartFactoryBean &&
					((SmartFactoryBean<?>) factory).isEagerInit());
		}
		if (isEagerInit) {
			getBean(beanName);
		}
	}
}

上面这段是初始化源码,很容易看到了,在根据beanname获取到这个bean的BeanDefinition后,会判断这个bean是不是一个factoryBean,如果是,则使用 &+beanname去做getBean操作。至于这个getBean细节不做详细赘述,意思是如果根据beanname可以获取到Object则直接返回,如果get不到,会基于当前beanname去做一个createBean操作,这样就解释了上述问题2:为什么annotationConfigApplicationContext.getBean("&factoryBeanTest")可以拿到FactoryBeanTest

那么我们在回到第一个问题,在annotationConfigApplicationContext.getBean(“factoryBeanTest”)的时候,为什么拿到的是TestSingleton,继续往下断点,
org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance
在这里插入图片描述
在这里插入图片描述
在这里我们单独拿出这个getObjectFromFactoryBean(factory, beanName, !synthetic);方法,发现出来的就是我们的TestSingleton对象了,那么继续往下看:
org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean
org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
关键的地方找到了,我来解释下,就是再容器初始话的时候调用getbean的时候会去创建一次bean,再创建的时候发现如果这个bean是FactoryBean类型的,则会调用FactoryBean的getObject方法,得到这个方法返回的对象,并且如果这个bean是单例的,会缓存到一个名为factoryBeanObjectCache的ConcurrentHashMap中,key(beanname)就是当前FactoryBean的beanname,下次拿的时候如果是原型的,则每次都会去调用FactoryBean的getObject方法拿到原型对象,如果是单例的,则直接在缓存factoryBeanObjectCache中根据beanname去拿到单例对象并返回。

据此,我们问题一也通过源码很好的解释了。(补充一句,在我们的spring-mybatis的核心源码中就使用了FactoryBean,有时间再来和大家分享一下!)

好了今天弄清楚了FactoryBean的相关问题,以及从源码的角度去分析了FactoryBean的作用以及spring内部是如何运行的,希望对大家有所帮助,同时有不足之处还望大家多多指正!

发布了47 篇原创文章 · 获赞 97 · 访问量 6万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章