前提
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 FactoryBean
和BeanFactoryUtils.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創建代理對象在原對象基礎上處理其他內容。那麼代理對象和工廠模式,裝飾模式又有什麼不同呢?之後的文章中慢慢解答,請關注哈!