Spring中FactoryBean源碼分析(最詳細)

        這篇文章我們來分析一下從容器中拿FactoryBean時,返回的爲什麼是FactoryBean所包裹的對象,關於FactoryBean的使用,請移步:Spring中FactoryBean的使用這篇文章。將Spring中FactoryBean的使用中的例子拿過來作爲源碼分析的入口:

package com.luban.factoryBean;
@Component("schoolFactory")
public class SchoolFactoryBean implements FactoryBean {
	@Override
	public Object getObject() throws Exception {
		return new School();
	}
	@Override
	public Class<?> getObjectType() {
		return School.class;
	}
	@Override
	public boolean isSingleton() {
		return true;
	}
}
@Configuration
@ComponentScan("com.luban.factoryBean")
public class Config {	
}
public class Test {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext contextnew = new AnnotationConfigApplicationContext(Config.class);
		School school = (School) contextnew.getBean("schoolFactory");
		System.out.println(school);
		SchoolFactoryBean schoolFactoryBean = (SchoolFactoryBean) contextnew.getBean("&schoolFactory");
		System.out.println(schoolFactoryBean);
	}
}
打印結果:
com.luban.School@3834d63f
com.luban.factoryBean.SchoolFactoryBean@1ae369b7

      在將源碼之前先說幾個重要的點:

      1.Spring中所有的單例對象都會保存在一個Map中,這個類叫做DefaultSingletonBeanRegistry ,關於DefaultSingletonBeanRegistry 是Spring中bean工廠的一個抽象類,而singletonObjects 就是存放所有單實例bean的Map,所以說在進行掃描註解的時候,會把名稱爲schoolFactory的SchoolFactoryBean 類型的bean添加到singletonObjects (注意雖然我們是通過bean名稱爲schoolFactory,來拿到School對象的,但是在這個singletonObjects 中存放的卻是SchoolFactoryBean 類型的類)。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

	/** Cache of singleton objects: bean name --> bean instance */
	//用於存放完全初始化好的 bean從該緩存中取出的 bean可以直接使用
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of singleton factories: bean name --> ObjectFactory */
	//存放 bean工廠對象解決循環依賴
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	//存放原始的bean對象用於解決循環依賴,注意:存到裏面的對象還沒有被填充屬性
	/** Cache of early singleton objects: bean name --> bean instance */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

    //其他的進行省略
}

2. FactoryBean內部包裹的類是存在一個FactoryBeanRegistrySupport類的名稱叫做factoryBeanObjectCache的Map中的,關於FactoryBeanRegistrySupport是DefaultSingletonBeanRegistry 的子類,在AnnotationConfigApplicationContext 中有個bean工廠會間接的繼承FactoryBeanRegistrySupport。

public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {

	/** Cache of singleton objects created by FactoryBeans: FactoryBean name --> object */
    //緩存factoryBean包裹的Object對象
	private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
    
    //省略其他部分
}

    3.通過截圖真實的比較一下差異

     我們可以看到在未執行School school = (School) contextnew.getBean("schoolFactory")之前,factoryBeanObjectCache 中是沒有數據的。

    

     當斷點執行到http://SchoolFactoryBean schoolFactoryBean = (SchoolFactoryBean) contextnew.getBean("&schoolFactory")時,factoryBeanObjectCache 有了一條數據。

        

     4. 所以當我們向Spring中注入FactoryBean類型的bean,相當於注入了兩個bean(另外一個雖然不在singletonObjects中,但是也受Spring的管理),並且被FactoryBean包裹的bean具有天然的懶加載功能,通過上圖得知的。

     5.在singletonObjects中的schoolFactory類型爲SchoolFactoryBean的bean,和普通的bean注入容器的方式一樣,也可以從上圖得知,在Spring進行掃描並注入到Spring容器的時候不回去考慮是不是FactoryBean類型的bean,所以注入到容器的過程就不在分析,在此只分析getBean的過程。

FactoryBean源碼分析:

public class Test {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext contextnew = new AnnotationConfigApplicationContext(Config.class);
		School school = (School) contextnew.getBean("schoolFactory");
		System.out.println(school);
		SchoolFactoryBean schoolFactoryBean = (SchoolFactoryBean) contextnew.getBean("&schoolFactory");
		System.out.println(schoolFactoryBean);
	}
}

   首先入口爲contextnew.getBean("schoolFactory")方法,然後會調用到AbstractApplicationContext#getBean方法:

        @Override
	public Object getBean(String name) throws BeansException {
                //判斷容器是否處於激活狀態
		assertBeanFactoryActive();
                //首先獲得容器,然後調用容器的getBean方法
		return getBeanFactory().getBean(name);
	}

  AbstractBeanFactory#getBean

@Override
public Object getBean(String name) throws BeansException {
     return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	/**
	 * 通過 name 獲取 beanName。這裏不使用 name 直接作爲 beanName 有兩個原因
	 * 1、name 可能會以 & 字符開頭,表明調用者想獲取 FactoryBean 本身,而非 FactoryBean
	 *   實現類所創建的 bean。在 BeanFactory 中,FactoryBean 的實現類和其他的 bean 存儲
	 *   方式是一致的,即 <beanName, bean>,beanName 中是沒有 & 這個字符的。所以我們需要
	 *   將 name 的首字符 & 移除,這樣才能從緩存裏取到 FactoryBean 實例。
	 * 2、還是別名的問題,轉換需要
	 * 如果name是以 & 字符開頭,那麼轉換後的值賦給了beanName,此時beanName 對應得是singletonObjects裏面的key
	 */
	final String beanName = transformedBeanName(name);
	Object bean;

	// Eagerly check singleton cache for manually registered singletons.
	/**
	 * 這個方法在初始化的時候會調用,在getBean的時候也會調用
	 * 爲什麼需要這麼做呢?
	 * 也就是說spring在初始化的時候先獲取這個對象
	 * 判斷這個對象是否被實例化好了(普通情況下絕對爲空====有一種情況可能不爲空)
	 * 從spring的bean容器中獲取一個bean,由於spring中bean容器是一個map(singletonObjects)
	 * 所以你可以理解getSingleton(beanName)等於beanMap.get(beanName)
	 * 由於方法會在spring環境初始化的時候(就是對象被創建的時候調用一次)調用一次
	 * 還會在getBean的時候調用一次
	 * 所以再調試的時候需要特別注意,不能直接斷點在這裏,
	 * 需要先進入到annotationConfigApplicationContext.getBean(IndexDao.class)
	 * 之後再來斷點,這樣就確保了我們是在獲取這個bean的時候調用的
	 *
	 * 需要說明的是在初始化時候調用一般都是返回null
       * 因爲我們這次實是在容器加載之後進行的,所以可以從容器中直接拿到對象
	 */
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		/**
		 * 如果 sharedInstance 是普通的單例 bean,下面的方法會直接返回。但如果
		 * sharedInstance 是 FactoryBean 類型的,則需調用 getObject 工廠方法獲取真正的
		 * bean 實例。如果用戶想獲取 FactoryBean 本身,這裏也不會做特別的處理,直接返回
		 * 即可。畢竟 FactoryBean 的實現類本身也是一種 bean,只不過具有一點特殊的功能而已。
             * 如果name傳過來的是以&開頭的或者是別名,那麼name和beanName就不相等了,beanName是轉換後的值
		 */
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}

	else {
		//省略從單例池中獲取不到時,開始創建bean的過程
	}
	return (T) bean;
}

       我們來看一下getSingleton是如何拿到緩存的bean的,執行DefaultSingletonBeanRegistry#getSingleton方法

@Override
@Nullable
public Object getSingleton(String beanName) {
	return getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	//從map中獲取bean如果不爲空直接返回,不再進行初始化工作
      //因爲在singletonObject中能夠拿到對象,然後就直接返回了
	Object singletonObject = this.singletonObjects.get(beanName);
        //下面這段代碼會在循環依賴中應用到,先不介紹
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
					singletonObject = singletonFactory.getObject();
					this.earlySingletonObjects.put(beanName, singletonObject);
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

    在判斷sharedInstance不爲空的時候,會進入getObjectForBeanInstance進行進一步判斷,AbstractBeanFactory#getObjectForBeanInstance

protected Object getObjectForBeanInstance(
        Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
 
    // Don't let calling code try to dereference the factory if the bean isn't a factory.
    // 如果name以“&”爲前綴,但是beanInstance不是FactoryBean,則拋異常
	if (BeanFactoryUtils.isFactoryDereference(name)) {
		if (beanInstance instanceof NullBean) {
			return beanInstance;
		}
		if (!(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
		}
	}
    // 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(也就是普通bean),則直接返回beanInstance
    // 如果beanInstance是FactoryBean,並且name以“&”爲前綴,則直接返回beanInstance(以“&”爲前綴代表想獲取的是FactoryBean本身)
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }
 
    // 走到這邊,代表beanInstance是FactoryBean,但name不帶有“&”前綴,表示想要獲取的是FactoryBean創建的對象實例
    Object object = null;
    if (mbd == null) {
        //如果mbd爲空,則嘗試從factoryBeanObjectCache緩存中獲取該FactoryBean創建的對象實例
        object = getCachedObjectForFactoryBean(beanName);
    }
 
    if (object == null) {
        // Return bean instance from factory.
        // 只有beanInstance是FactoryBean才能走到這邊,因此直接強轉
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        if (mbd == null && containsBeanDefinition(beanName)) {
            // mbd爲空,但是該bean的BeanDefinition在緩存中存在,則獲取該bean的MergedBeanDefinition
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        // mbd是否是合成的(這個字段比較複雜,mbd正常情況都不是合成的,也就是false,什麼時候纔是合成的,當使用AOP動態代理生成的bean,這個字段就是true
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        //從FactoryBean獲取對象實例,這句是關鍵代碼
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    // 返回對象實例
    return object;
}

@Nullable
protected Object getCachedObjectForFactoryBean(String beanName) {
    //可以看到就是從factoryBeanObjectCache裏面取已經緩存的,這樣第二次再去獲取的時候不用再次創建
	return this.factoryBeanObjectCache.get(beanName);
}

        讓我們來看一下FactoryBeanRegistrySupport#getObjectFromFactoryBean方法:

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
	// 1.如果是單例,並且已經存在於單例對象緩存中,什麼意思?
	//就是說FactoryBean你可以在類上標註爲多實例的bean,那麼在多次獲取FactoryBean的時候
	//實際就是多次調用FactoryBean的getObject方法,如果是單實例的,則進行緩存起來,只創建一次
	if (factory.isSingleton() && containsSingleton(beanName)) {
		//2.加鎖進行操作
		synchronized (getSingletonMutex()) {
			// 3.從FactoryBean創建的單例對象的緩存中獲取該bean實例
			//關於這個factoryBeanObjectCache上面我們已經介紹過了
			Object object = this.factoryBeanObjectCache.get(beanName);
			if (object == null) {
				// 4.調用FactoryBean的getObject方法獲取對象實例
				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);
				// 5.如果該beanName已經在緩存中存在,則將object替換成緩存中的
				if (alreadyThere != null) {
					object = alreadyThere;
				}
				else {
					//6.判斷需要做後置處理,shouldPostProcess傳過來的是!synthetic,即爲true,不是合成的
					//如果是合成的,就不需要做後置處理的。爲什麼?原因是這個後置處理就是判斷是否需要對類進行AOP增強的
					if (shouldPostProcess) {
						if (isSingletonCurrentlyInCreation(beanName)) {
							// Temporarily return non-post-processed object, not storing it yet..
							return object;
						}
						beforeSingletonCreation(beanName);
						try {
							// 7.對bean實例進行後置處理,執行所有已註冊的BeanPostProcessor的postProcessAfterInitialization方法
							//此方法會進行AOP代理增強,所以我們在寫AOP增強的時候,不只是會增強FactoryBean本身,還會增強FactoryBean所包裹的對象
							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)) {
						// 8.將beanName和object放到factoryBeanObjectCache緩存中
						this.factoryBeanObjectCache.put(beanName, object);
					}
				}
			}
			// 9.返回object對象實例
			return object;
		}
	}
	else {
		// 10.調用FactoryBean的getObject方法獲取對象實例
		//可以看出來,如果是多實例的,那麼每次是直接創建的
		Object object = doGetObjectFromFactoryBean(factory, beanName);
		if (shouldPostProcess) {
			try {
				// 11.對bean實例進行後置處理,執行所有已註冊的BeanPostProcessor的postProcessAfterInitialization方法
				object = postProcessObjectFromFactoryBean(object, beanName);
			}
			catch (Throwable ex) {
				throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
			}
		}
		// 12.返回object對象實例
		return object;
	}
}

      上述代碼中的4會調用FactoryBean的getObject方法獲取對象實例

      上述代碼中的7會對bean實例進行後置處理

      代碼如下:

      FactoryBeanRegistrySupport#doGetObjectFromFactoryBean方法

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

	Object object;
	try {
		// 1.調用FactoryBean的getObject方法獲取bean對象實例
		if (System.getSecurityManager() != null) {
			AccessControlContext acc = getAccessControlContext();
			try {
				// 1.1 帶有權限驗證的
				object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
			// 1.2 不帶權限,factory.getObject就會最終執行我們實現了FactoryBean的方法
			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.
	// 2.getObject返回的是空值,並且該FactoryBean正在初始化中,則直接拋異常,不接受一個尚未完全初始化的FactoryBean的getObject返回的空值
	if (object == null) {
		if (isSingletonCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(
					beanName, "FactoryBean which is currently in creation returned null from getObject");
		}
		object = new NullBean();
	}
	// 3.返回創建好的bean對象實例
	return object;
}

       很簡單的方法,就是直接調用 FactoryBean 的 getObject 方法來獲取到對象實例。

       調用 FactoryBeanRegistrySupport#postProcessObjectFromFactoryBean方法,主要是對bean進行後置後置增強的。

@Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
    return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
 
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {
 
    Object result = existingBean;
    // 1.遍歷所有註冊的BeanPostProcessor實現類,調用postProcessAfterInitialization方法
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        // 2.在bean初始化後,調用postProcessAfterInitialization方法
        result = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (result == null) {
            // 3.如果返回null,則不會調用後續的BeanPostProcessors
            return result;
        }
    }
    return result;
}

總結:

     1. 在取FactoryBean包裹的對象時(也就是不加&),先對名字進行轉換,獲取真正的beanName,然後從singletonObjects中取出bean實例,判斷這個bea是否是否爲FactoryBean類型的,如果是的話,在判斷是單實例還是多實例的,如果是多實例的,則直接調用FactoryBean的getObject方法,如果單實例的,則先從factoryBeanObjectCache緩存中去拿,沒有的話則進行創建,創建完成後,會判斷這個FactoryBean的bd是不是合成,如果不是則執行BeanPostProcessor後置處理器的postProcessAfterInitialization進行增強(如果需要增強的話)。

     2.FactoryBean包裹的對象是天然懶加載的,如果是單例的,則會在第一個調用getBean的時候創建,然後放到緩存中

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