這篇文章我們來分析一下從容器中拿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的時候創建,然後放到緩存中