【源碼Spring系列】——徹底搞懂BeanFactory和FactoryBean不同

前提

        BeanFactory和FactoryBean在學習Spring源碼之前總是傻傻分不清,搞不懂兩者的區別,這次學習Spring源碼的過程,感覺自己開竅了,整理下相關點,希望可以幫助需要的朋友。

幾個概念要分清楚

何爲Bean?

        類比的方式 Java  Object 等同於 Spring Bean。Bean就是Spring中管理的對象。所以無論是BeanFactory還是FactoryBean,都是爲了操作Spring中的對象。之後在怎麼區分兩者呢,Java中常講的命名要規範,那Spring源碼命名絕對是典範,BeanFactory—— bean工廠,FactoryBean——工廠bean,兩者英譯漢的側重點,一個是工廠,另一個bean而已。

 BeanFactory

         BeanFactory定義了 IOC 容器的最基本形式,並提供了 IOC 容器應遵守的的最基本的接口,也就是 Spring IOC 所遵守的最底層和最基本的編程規範。在  Spring 代碼中, BeanFactory 只是個接口,並不是 IOC 容器的具體實現,但是 Spring 容器給出了很多種實現,如 DefaultListableBeanFactory 、XmlBeanFactory等。

          在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)來進行管理的,同樣Factory也是需要接受BeanFactory的管理。

FactoryBean

         FactoryBean而言,這個Bean不是簡單的Bean,而是一個能生產或者修飾對象生成的工廠Bean,它的實現與設計模式中的工廠模式和修飾器模式類似 、 ApplicationContext 等,都是附加了某種功能的實現。一個Bean如果實現了FactoryBean接口,那麼根據該Bean的名稱獲取到的實際上是getObject()返回的對象,而不是這個Bean自身實例,如果要獲取這個Bean自身實例,那麼需要在名稱前面加上'&'符號。下方簡單附一個FactoryBean的使用方式

@Component
public class MyFactoryBean implements FactoryBean {
   @Override
   public Object getObject() throws Exception {
      return new User();
   }

   @Override
   public Class<?> getObjectType() {
      return User.class;
   }
}

 System.out.println(context.getBean("myFactroyBean")); //User
 System.out.println(context.getBean("&myFactroyBean")); //MyFactroyBean

       上篇文章說每一個bean都一個對應的BeanDefinition,其中定義bean的相關屬性,再加上註冊器就可以實現Bean的創建,那麼爲什麼還要有一個FactoryBean同樣可以用來創建Bean呢?

         在某些情況下,實例化Bean過程比較複雜,如果按照傳統的方式,則需要在<bean>中提供大量的配置信息。配置方式的靈活性是受限的,這時採用編碼的方式可能會得到一個簡單的方案。Spring爲此提供了一個org.springframework.bean.factory.FactoryBean的工廠類接口,用戶可以通過實現該接口定製實例化Bean的邏輯。FactoryBean接口對於Spring框架來說佔用重要的地位,Spring自身就提供了70多個FactoryBean的實現。它們隱藏了實例化一些複雜Bean的細節,給上層應用帶來了便利。

       FactoryBean就相當於Spring提供外界的一個暴露點,通過它完整複雜Bean的實例化。

FactoryBean實現原理

// org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
         //獲取bean真正的名稱
		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
        //從單例對象池拿到bean實例
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
// 以下邏輯省略,如有需要自行查看源碼
}

transformedBeanName(name)是爲了獲取Bean真正的名稱,它會去掉name前面的'&',而getSingleton(beanName)是從父類容器singletonObjects中取的這個Bean的實例。在Spring中還有很多這樣的容器,比如DefaultListableBeanFactory中的beanDefinitionMap,它就是的IOC容器真正保存Bean的地方,它是一個CurrentHashMap。類似的還有FactoryBeanRegistrySupport中的factoryBeanObjectCache等。

拿到sharedInstance後,後面的一大堆操作做了單例、多例等判斷,最終會走到this.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.
        //判斷name是否不爲空且以&開頭
		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.
        //判斷的是beanInstance是否屬於FactoryBean或其子類的實例
		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd != null) {
			mbd.isFactoryBean = true;
		}
		else {
			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());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

上述邏輯關鍵點 beanInstance instanceof FactoryBeanBeanFactoryUtils.isFactoryDereference(name)。如果beanInstance不屬於FactoryBean或其子類的實例,或者name是以&開頭就直接返回實例對象beanInstance,否則進入到if分支中。分支中重點

object = getObjectFromFactoryBean(factory, beanName, !synthetic);

具體邏輯如下

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;
		}
	}

這段邏輯中大概的意思就是目的是從factoryBeanObjectCache中獲得FactoryBean,無論是否能拿到if else中邏輯都會執行object = doGetObjectFromFactoryBean(factory, beanName);

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final 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);
		}

關鍵點

object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);

這個factory就是我們傳入的beanInstance實例。繞了這麼一大圈,getBean方法返回的居然是我們實現FactoryBean接口定義的getObject方法。這剛好和上方的描述相呼應了。

額外解釋下 factoryBeanObjectCache 是什麼?

/** Cache of singleton objects created by FactoryBeans: FactoryBean name to object. */
	private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);

通過這個定義和源碼中註釋可以得知 factoryBeanObjectCache中存儲的FactoryBean,在getObjectForBeanInstance()中有段邏輯

object = getCachedObjectForFactoryBean(beanName);
/**
	 * Obtain an object to expose from the given FactoryBean, if available
	 * in cached form. Quick check for minimal synchronization.
	 * @param beanName the name of the bean
	 * @return the object obtained from the FactoryBean,
	 * or {@code null} if not available
	 */
	@Nullable
	protected Object getCachedObjectForFactoryBean(String beanName) {
		return this.factoryBeanObjectCache.get(beanName);
	}

如果以&開頭就直接返回實例對象beanInstance,beanInstance則是從factoryBeanObjectCache中獲取的,由此也知道FactoryBean本身並不存儲到單例對象池中,獲取本身爲需要加&用於區分。

       主要介紹BeanFactory和FactoryBean在命名上區分,在Spring中不同的作用,以及FactoryBean的實驗原理。FactoryBean在Spring中存在的意義爲了解決配置方式裝配bean靈活性是受限的問題,通過編碼得到一個簡單的方案。

      關於FactoryBean的使用場景,特別像代理模式的實現方案,藉助FactoryBean創建代理對象在原對象基礎上處理其他內容。那麼代理對象和工廠模式,裝飾模式又有什麼不同呢?之後的文章中慢慢解答,請關注哈!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章