spring原始碼學習之旅(二) 結合原始碼聊聊FactoryBean
阿新 • • 發佈:2021-07-16
一、什麼是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時
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的區別
四、FactoryBean的實際運用場景
希望每get一個知識點都能堅持用部落格記錄下來,加油!