上一篇講到了BeanFactory,那就不得不提一下FactoryBean,先看一下它的定義吧!
定義
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
//返回的對(duì)象實(shí)例
@Nullable
T getObject() throws Exception;
//返回對(duì)象類型
@Nullable
Class<?> getObjectType();
//getObject返回的對(duì)象是否單例。true代表單例,false代表非單例
default boolean isSingleton() {
return true;
}
}
看到里面的三個(gè)方法名,我們可以見(jiàn)名知意了。Bean實(shí)例、Bean類型、bean是否單例。那接下來(lái)我們就實(shí)現(xiàn)FactoryBean 接口,看看是怎么使用 FactoryBean 的,然后再?gòu)脑创a的角度去看看 Spring 是怎么解析FactoryBean 中的 Bean 的。
實(shí)踐
GongjFactoryBean
GongjFactoryBean 實(shí)現(xiàn) FactoryBean ,并重寫其三個(gè)方法。
@Component
public class GongjFactoryBean implements FactoryBean {
/**
* 當(dāng)該Bean是單例時(shí),該方法只執(zhí)行一次
* @return
* @throws Exception
*/
@Override
public Object getObject() throws Exception {
User user = new User();
System.out.println("====" + user);
return user;
}
@Override
public Class<?> getObjectType() {
return User.class;
}
/**
* 可以控制該Bean的作用域是單例還是原型
* @return
*/
@Override
public boolean isSingleton() {
return true;
}
}
AppConfig
新建AppConfig作為啟動(dòng)掃描類
@ComponentScan("com.gongj")
public class AppConfig {
}
Main
使用 AnnotationConfigApplicationContext 容器啟動(dòng) Spring
public class Main {
public static void main(String[] args) {
//啟動(dòng)spring容器 ----> 創(chuàng)建非懶加載的單例Bean
//掃描包路徑
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println(annotationConfigApplicationContext.getBean("gongjFactoryBean")); System.out.println(annotationConfigApplicationContext.getBean("gongjFactoryBean"));
System.out.println(annotationConfigApplicationContext.getBean("&gongjFactoryBean"));
System.out.println(annotationConfigApplicationContext.getBean("&gongjFactoryBean"));
}
}
啟動(dòng)main方法輸出以下結(jié)果:
====com.gongj.entity.User@cac736f #這是我在GongjFactoryBean中進(jìn)行打印的
com.gongj.entity.User@cac736f
com.gongj.entity.User@cac736f
com.gongj.service.GongjFactoryBean@5e265ba4
com.gongj.service.GongjFactoryBean@5e265ba4
通過(guò)上面啟動(dòng)的這個(gè)例子我們可以得出以下幾個(gè)結(jié)論:
- GongjFactoryBean#getObject()函數(shù)只執(zhí)行一次
- 根據(jù) gongjFactoryBean 獲取的是 User 對(duì)象并每次獲取的 User 對(duì)象一致。
- 根據(jù) &gongjFactoryBean 獲取的是 GongjFactoryBean 對(duì)象并每次獲取的 GongjFactoryBean 對(duì)象一致。
初步懷疑該現(xiàn)象是 isSingleton 函數(shù)進(jìn)行控制的。那我接下來(lái)將isSingleton函數(shù)返回的值修改為false。
@Override
public boolean isSingleton() {
return false;
}
再次執(zhí)行main方法,輸出以下結(jié)果:
====com.gongj.entity.User@cac736f #這是我在GongjFactoryBean中進(jìn)行打印的
com.gongj.entity.User@cac736f
====com.gongj.entity.User@5e265ba4 #這是我在GongjFactoryBean中進(jìn)行打印的
com.gongj.entity.User@5e265ba4
com.gongj.service.GongjFactoryBean@156643d4
com.gongj.service.GongjFactoryBean@156643d4
通過(guò)上面啟動(dòng)的這個(gè)例子我們又可以得出以下幾個(gè)結(jié)論:
- isSingleton() 函數(shù)控制的是以
gongjFactoryBean獲取的對(duì)象是否是單例的。 - isSingleton() 函數(shù)的修改不影響以
&gongjFactoryBean獲取的對(duì)象,它還是單例的。
看到這我們應(yīng)該就有疑惑了,讓我們帶著疑惑開始一步一步DEGUG源碼。
將 isSingleton() 函數(shù)的返回值修改為true。

根據(jù)上圖我們可以得出結(jié)論:
- GongjFactoryBean 在啟動(dòng)的時(shí)候就已經(jīng)加入到 Spring 容器中。很顯然 GongjFactoryBean 是一個(gè)非懶加載的單例 Bean。
調(diào)試
- 進(jìn)入
AbstractApplicationContext#getBean
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name); 》》
}
-
AbstractBeanFactory#getBean
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false); 》》
}
-
AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 對(duì)beanName進(jìn)行轉(zhuǎn)換 name如果是"&gongjFactoryBean",那么beanName就是"gongjFactoryBean"
final String beanName = transformedBeanName(name); 》》
Object bean;
//根據(jù)beanName去單例池中獲取單例Bean
Object sharedInstance = getSingleton(beanName); 》》
if (sharedInstance != null && args == null) {
//.....省略代碼
// 判斷sharedInstance是不是FactoryBean,
// 如果是FactoryBean,那么真正需要拿到的是getObject方法所返回的對(duì)象
//beanName 是spinrg進(jìn)行解析后獲取到的BeanName
//name 我們手動(dòng)傳入的beanName
//sharedInstance 根據(jù)beanName獲取到的單例Bean對(duì)象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); 》》
}
else{
//....省略代碼 下篇分析
}
}
-
AbstractBeanFactory#transformedBeanName
先調(diào)用BeanFactoryUtils.transformedBeanName方法,然后拿到返回值,再執(zhí)行canonicalName方法。
//返回beanName,去掉傳入name的&前綴,并且把返回的name當(dāng)做別名去aliasMap中尋找原始的beanName
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
BeanFactoryUtils#transformedBeanName
private static final Map<String, String> transformedBeanNameCache = new ConcurrentHashMap<>();
String FACTORY_BEAN_PREFIX = "&";
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
// 如果beanName沒(méi)有以&開頭,則直接返回
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { // gongjFactoryBean
return name;
}
// 如果beanName以&開頭,截取&后的beanName,并且把截取前后的name存在transformedBeanNameCache 中
//可能會(huì)有多個(gè)&&&,循環(huán)截取
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
SimpleAliasRegistry#canonicalName
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
public String canonicalName(String name) {
String canonicalName = name;
String resolvedName;
do {
//根據(jù)傳遞過(guò)來(lái)的beanName,去別名Map中查找 獲取出來(lái)就是真正的BeanName 例如:gjfg = gongjFactoryBean
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
transformedBeanName 方法到此結(jié)束!
- getSingleton
再來(lái)看一下 Spring 是如何根據(jù) beanName 去單例池中獲取單例Bean
@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 從單例池中獲取實(shí)例 singletonObjects 一級(jí)緩存
Object singletonObject = this.singletonObjects.get(beanName);
// 如果從單例池中沒(méi)有獲取到實(shí)例 并且指定的單例bean正在創(chuàng)建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//鎖定全局變量并進(jìn)行處理
synchronized (this.singletonObjects) {
//earlySingletonObjects 二級(jí)緩存
singletonObject = this.earlySingletonObjects.get(beanName);
// 沒(méi)有從二級(jí)緩存中獲取到
if (singletonObject == null && allowEarlyReference) {
//當(dāng)某些方法需要提前初始化的時(shí)候,會(huì)調(diào) addSingletonFactory 方法將對(duì)
//ObjectFactory 初始化存儲(chǔ)在 singletonFactories Map中
// singletonFactories 三級(jí)緩存
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//記錄在緩存中 earlySingletonObjects與singletonFactories互斥
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
這個(gè)方法首先嘗試從 singletonObjects(一級(jí)緩存) 里面獲取實(shí)例,如果取不到再?gòu)?code>earlySingletonObjects(二級(jí)緩存) 里面獲取,如果還獲取不到,再嘗試從 singletonFactories(三級(jí)緩存) 里面獲取 beanName 對(duì)應(yīng)的 ObjectFactory,然后調(diào)用這個(gè) ObjectFactory 的 getObject 方法來(lái)獲取 bean ,并放到 earlySingletonObjects(二級(jí)緩存) 里面 ,并且從singletonFacotories(三級(jí)緩存) 里面 remove 掉這個(gè) ObjectFactorγ。
- singletonObjects :?jiǎn)卫龑?duì)象的緩存:Bean名稱到Bean實(shí)例,也就是常說(shuō)的單例池(一級(jí)緩存)。
- singletonFacotories :?jiǎn)卫S的緩存(三級(jí)緩存), Bean名稱到ObjectFactory,一旦最終對(duì)象被創(chuàng)建(通過(guò)objectFactory.getObject()),此引用信息將刪除
- earlySingletonObjects :用于存儲(chǔ)在創(chuàng)建Bean早期對(duì)創(chuàng)建的原始bean的一個(gè)引用(二級(jí)緩存),注意這里是原始bean,即使用工廠方法或構(gòu)造方法創(chuàng)建出來(lái)的對(duì)象,一旦對(duì)象最終創(chuàng)建好,此引用信息將刪除
getSingleton 方法到此結(jié)束!
-
AbstractBeanFactory#getObjectForBeanInstance
關(guān)鍵部分就在這個(gè)方法中,進(jìn)入方法代碼
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// name也就是我傳入的beanName 如果是以&符號(hào)開頭,則直接返回單例池(SingletonObjects)中的對(duì)象
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
//判斷單例對(duì)象beanInstance是否實(shí)現(xiàn)了FactoryBean,如果沒(méi)有拋出異常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
// 返回單例池(SingletonObjects)中的對(duì)象
return beanInstance;
}
// 如果 beanInstance 不是 FactoryBean,則直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
//根據(jù)真正的BeanName從factoryBeanObjectCache緩存中獲取Bean對(duì)象
object = getCachedObjectForFactoryBean(beanName);
}
// 從factoryBeanObjectCache中沒(méi)有拿到則進(jìn)行創(chuàng)建
if (object == null) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
//從beanDefinitionMap判斷該Bean是否存在
if (mbd == null && containsBeanDefinition(beanName)) {
//進(jìn)行Bean合并
mbd = getMergedLocalBeanDefinition(beanName);
}
//是否是用戶定義的而不是應(yīng)用程序本身定義的
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 調(diào)用getObject方法得到對(duì)象
object = getObjectFromFactoryBean(factory, beanName, !synthetic); 》》
}
return object;
}
FactoryBeanRegistrySupport#getObjectFromFactoryBean
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 是不是單例的 && 根據(jù) beanName 判斷該名稱在 singletonObjects(單例池) 中是否存在
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 調(diào)用getObject方法得到一個(gè)對(duì)象
object = doGetObjectFromFactoryBean(factory, beanName); 》》
//再?gòu)木彺嬷蝎@取一遍
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
//返回指定的單例bean當(dāng)前是否正在創(chuàng)建中
if (isSingletonCurrentlyInCreation(beanName)) {
return object;
}
//表示這些bean正常創(chuàng)建中,在沒(méi)創(chuàng)建完時(shí)不能重復(fù)創(chuàng)建
beforeSingletonCreation(beanName);
try {
// 調(diào)用BeanPostProcessor執(zhí)行初始化后的邏輯,主要就是進(jìn)行AOP
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)) {
//將創(chuàng)建的Bean放入factoryBeanObjectCache
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
// 多例 每次都創(chuàng)建一個(gè),不從factoryBeanObjectCache中獲取
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;
}
}
-
FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
在doGetObjectFromFactoryBean方法中我們終于看到了我們想要看到的方法,也就是object = factory.getObject();
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 {
//調(diào)用了FectoryBean里的getObject()函數(shù)
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);
}
// 如果調(diào)用getObject()方法返回的是null,那么則返回一個(gè)NullBean
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 就結(jié)束啦!當(dāng)然 getBean 方法才看到冰山一角。
FactoryBean是一個(gè)能生產(chǎn)或修飾對(duì)象生成的工廠 Bean。一個(gè) Bean 如果實(shí)現(xiàn)了 FactoryBean 接口,那么根據(jù)該 Bean 的名稱獲取到的實(shí)際上是 getObject()返回的對(duì)象,而不是這個(gè) Bean 自身實(shí)例,如果要獲取這個(gè)Bean自身實(shí)例,那么需要在名稱前面加上'&'符號(hào)。