一、什麼是FactoryBean
FactoryBean是由spring提供的用來讓用戶可以自定bean創建的接口;實現該接口可以讓你的bean不用經過spring複雜的bean創建過程,但同時也能做到拿來即用,按需加載;該接口提供的方法如下:
/**
* 獲取FactoryBean管理的對象的實例 一般由spring自動調用 無需手動調用
*/
T getObject() throws Exception;
/**
* 獲取FactoryBean管理的對象的類型
*/
Class<?> getObjectType();
/**
* 判斷FactoryBean管理的對象是否是單例 默認爲單例
* 如果返回爲false,則spring不會使用factoryBeanObjectCache來緩存已加載的對象實例,
* 每次都會創建一個全新的對象
*/
default boolean isSingleton() {
return true;
}
二、FactoryBean在spring中的加載過程
測試環境準備:
- 自定義一個FactoryBean實現類,返回對應的測試實例Person類,代碼如圖:
- 爲了便於代碼debug,使用xml的配置方式進行配置,如圖:
- 啓動代碼如下:通過以上環境debug可以發現,當spring容器加載完後在BeanFactory的一級緩存singletonObjects中有myFactoryBean而並沒有person類的實例,那ac.getBean("myFactoryBean")是怎麼拿到Person的呢我們可以通過剖析getBean("myFactoryBean")這個方法來進行分析:當spring想要獲取某個bean的時候,首先會從緩存中獲取這個bean(參加org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)),當需要獲取myFactoryBean時,由於xml中有對myFactoryBean的配置所以容器啓動的時候myFactoryBean就已經被存到緩存中去了,所以從緩存中能直接獲取,接下來會調用專門針對加載實現了FactoryBean接口的實現類的方法:getObjectForBeanInstance()==》getObjectFromFactoryBean()==》doGetObjectFromFactoryBean;其中會在doGetObjectFromFactoryBean中調用getObject方法返回具體的對象實例,getObjectFromFactoryBean方法中會根據isSingleton方法的具體實現判斷要不要把對應實例加載到factoryBeanObjectCache緩存中;下面貼上這個三個核心方法的方法簽名和源碼:
org.springframework.beans.factory.support.AbstractBeanFactory#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.
* 判斷是否是FactoryBean的子接口,是則設置isFactoryBean爲true並返回
*/
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.
// 判斷我們拿到的bean實例是不是factoryBean,如果不是直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 從factoryBean的緩存factoryBeanObjectCache中嘗試獲取bean信息
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());
// 調用getObject獲取factoryBean管理的bean實例
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean:
點擊查看代碼
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;
}
}
org.springframework.beans.factory.support.FactoryBeanRegistrySupport#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 {
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和BeanFactory的區別
- BeanFactoryBeanFactory是spring定義的創建bean的一個頂層父接口,其定義了獲取bean的方法,咱們常見的ApplicationContext和DefaultListableBeanFactory都間接實現了它;實現了BeanFactory意味着創建的bean必須要經過spring定義的複雜的各種生命週期方法;
- FactoryBeanFactoryBean同樣可以創建bean,但是其管理的bean可以不經過spring定義的創建的bean的生命週期,也可以不通過反射直接獲取;可以針對不同的需求定製化FactoryBean,相當於一個創建工廠的bean,而這個工廠bean又可以創建不同的對象實例
四、FactoryBean的實際運用場景
據我所知像Mybatis,dubbo以及springcloud這些開源框架中都有使用factoryBean來創建對象,但是由於本人並沒有去看這些框架的源碼也沒有過多的瞭解所以這裏暫且不表,所以在這裏貼一個通過FactoryBean創建定時任務的例子;
項目中定時任務的使用還是比較頻繁的,設置有時候會多到專門開一個服務器去跑這些定時任務,而定時任務無非關注幾點,一是任務的間隔時間,二是任務的執行邏輯;
- 定義一個CommonTask來統一管理任務的間隔時間以及具體執行的service;
- 定義TaskFactoryBean實現FactoryBean接口,用來生成CommonTask的實例
- 定義一個TaskConfig類用來按需生成不同的CommonTask以上只是提供了粗略的實現思路,具體的等抽空補代碼。。。