天天看點

BeanFactory和FactoryBean接口的差別

Spring版本:5.1.3.RELEASE

BeanFactory

接口:

String FACTORY_BEAN_PREFIX = "&";
	Object getBean(String name) throws BeansException;
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;
	Object getBean(String name, Object... args) throws BeansException;
	<T> T getBean(Class<T> requiredType) throws BeansException;
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
	<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
	boolean containsBean(String name);
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;
	String[] getAliases(String name);
           
是簡單工廠模式的應用,根據傳入的beanName執行個體化相應的執行個體。

JavaDoc翻譯(使用Google翻譯并加以潤色,如有歧義歡迎指出):

用于通路Spring bean容器的根接口。 這是bean容器的基本用戶端視圖; 其他接口(如ListableBeanFactory和org.springframework.beans.factory.config.ConfigurableBeanFactory)可用于特定目的。

該接口被一些持有bean定義的對象實作,每個bean定義由一個字元串名稱唯一辨別。

根據bean定義,工廠将傳回包含對象的獨立執行個體(Prototype設計模式)或單個共享執行個體(Singleton設計模式的進階替代,其中執行個體是工廠範圍中的單例)。

将傳回哪種類型的執行個體取決于bean工廠配置:API是相同的。

從Spring 2.0開始,根據具體的應用程式上下文(例如Web環境中的“request”和“session”範圍),可以使用更多的scope(範圍)。

這種方法的重點是BeanFactory是應用元件的注冊中心和集中的配置中心(例如,不再需要單個對象去讀取屬性檔案)。

有關此方法的優點的讨論,請參見"Expert One-on-One J2EE Design and Development"的第4章和第11章。

請注意,依靠依賴注入(“push”配置)通過setter或構造函數來配置應用對象通常更好,而不是像BeanFactory查找一樣的使用“pull”配置的任意方式。Spring的依賴注入功能是使用這個BeanFactory接口及其子接口實作的。

通常,BeanFactory将加載存儲在配置源(例如XML文檔)中的bean定義,并使用org.springframework.beans包來配置bean。盡管如此,一種簡單地實作是直接在Java代碼中傳回Java對象。如何存儲定義沒有限制:LDAP,RDBMS,XML,屬性檔案等。鼓勵實作支援bean之間的引用(依賴注入)。

與ListableBeanFactory中的方法相反,如果這是HierarchicalBeanFactory,則此接口中的所有操作也将檢查父工廠。如果在此工廠執行個體中找不到bean,則會詢問直接父工廠(從父類bean工廠中擷取)。此工廠執行個體中的Bean應該在任何父工廠中覆寫同名的Bean。

Bean工廠實作應盡可能支援标準bean生命周期接口。 完整的初始化方法及其标準順序是:

  1. BeanNameAware 接口的 setBeanName 方法
  2. BeanClassLoaderAware 接口的 setBeanClassLoader 方法
  3. BeanFactoryAware 接口的 setBeanFactory 方法
  4. EnvironmentAware 接口的 setEnvironment 方法
  5. EmbeddedValueResolverAware 接口的 setEmbeddedValueResolver 方法
  6. ResourceLoaderAware 接口的 setResourceLoader 方法 (僅适用于在應用程式上下文(Application Context)中運作時)
  7. ApplicationEventPublisherAware 接口的 setApplicationEventPublisher 方法 (僅适用于在應用程式上下文(Application Context)中運作時)
  8. MessageSourceAware 接口的 setMessageSource 方法 (僅适用于在應用程式上下文(Application Context)中運作時)
  9. ApplicationContextAware 接口的 setApplicationContext 方法 (僅适用于在應用程式上下文(Application Context)中運作時)
  10. ServletContextAware 接口的 setServletContext 方法 (僅适用于在應用程式上下文(Application Context)中運作時)
  11. 所有實作了BeanPostProcessor接口的類的 postProcessBeforeInitialization 方法
  12. InitializingBean 接口的 afterPropertiesSet 方法
  13. 自定義的init方法
  14. 所有實作了BeanPostProcessor接口的類的 postProcessAfterInitialization 方法

關閉Bean工廠時,應用以下生命周期方法:

  1. 所有實作了DestructionAwareBeanPostProcessor接口的類的 postProcessBeforeDestruction 方法
  2. DisposableBean 接口的 destroy 方法
  3. 自定義的destroy 方法

Spring Bean生命周期圖:

BeanFactory和FactoryBean接口的差別
Spring 4.3.17.RELEASE 源碼的JavaDoc文檔寫的也是以上流程。跟其它網上的文章寫的流程有出入,應該以官方文檔為準。

FactoryBean

接口:

T getObject() throws Exception;
	Class<?> getObjectType();
	default boolean isSingleton() {
		return true;
	}
           
是工廠方法模式的應用,由子類實作相應的執行個體。

JavaDoc翻譯(使用Google翻譯并加以潤色,如有歧義歡迎指出):

接口被BeanFactory中使用的對象所實作,這些對象本身就是單個對象的工廠。如果bean實作了這個接口,它将被用作暴露此對象的工廠,而不是直接将自己作為bean執行個體給暴露出來。

注意:實作此接口的bean不能用作普通bean。

FactoryBean是被定義成bean的形式,但是bean對象的引用(getObject()方法獲得)始終是由它建立的。

FactoryBeans可以支援單例和原型,可以根據需要懶惰地建立對象,也可以在啟動時急切地建立對象。

SmartFactoryBean接口允許公開更細粒度的行為中繼資料。

該接口在架構内部大量使用,例如用于AOP的 org.springframework.aop.framework.ProxyFactoryBean類 或 org.springframework.jndi.JndiObjectFactoryBean類。

它也可以用于定制元件;但是,這僅适用于基礎架構代碼。

FactoryBean是一個programatic contract (程式設計合約)。實作不應該依賴annotation-driven (注解驅動)的注入或其他反射設施。

getObjectType()和getObject()方法的調用可能在引導過程的早期發生,甚至在所有的(post-processor)後置處理器設定之前。

如果您需要通路其他bean,請實作 BeanFactoryAware 并以程式設計方式擷取它們。

最後,FactoryBean對象參與包含BeanFactory的bean建立的同步。

除了FactoryBean本身(或類似)中的延遲初始化之外,通常不需要内部同步。

下面從源碼層面深入分析二者差別:

檢視 BeanFactory接口的抽象類 AbstractBeanFactory的getObjectForBeanInstance方法的實作:

protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
		// bean的name如果以&開頭,則是FactoryBean執行個體
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			// 驗證是否是FactoryBean對象,不是則抛出異常
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
			}
		}

		// 執行到此處,已經得到了bean執行個體,如果是普通的bean,或者是FacoryBean執行個體,直接傳回.
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd == null) {
		    // 從FactoryBeanObjectCache中擷取由FactoryBean建立的bean對象
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// beanInstance強轉為FactoryBean
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// 如果是單例,則緩存從FactoryBean擷取的對象
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			// 最終調用FactoryBean執行個體的getObject方法擷取bean執行個體
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}
           

在getObjectFromFactoryBean方法實作中會調用doGetObjectFromFactoryBean方法:

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
			throws BeanCreationException {

		Object object;
		try {
			if (System.getSecurityManager() != null) {
				AccessControlContext acc = getAccessControlContext();
				try {
				    // 調用FactoryBean的getObject方法來傳回執行個體
					object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
				}
				......
			}
			else {
			    // 調用FactoryBean的getObject方法來傳回執行個體
				object = factory.getObject();
			}
		}
	    ......
		return object;
	}
           

實作FactoryBean的類,在初始化放入容器後,通過BeanFactory的getBean方法調用時,會調用FactoryBean的getObject方法傳回對應的bean執行個體對象,而不是像普通的bean一樣直接傳回bean執行個體.

BeanFactory的常量&的作用是在擷取bean的時候直接傳回FactoryBean的bean執行個體,而不是調用的getObject方法傳回對應的bean執行個體.

以上,如有問題歡迎提出!

參考: https://blog.csdn.net/silk_bar/article/details/60967064