FactoryBean
友情提示:如果時間緊,任務重,可以直接查看頁面最後的總結。
一提到FactoryBean,大家可能會立馬想到BeanFactory,這兩個單詞已經被我混淆了不知多少次,總是記不住誰是誰的誰,這裡其實就記住他們的最後一個單詞去區分他們就好了(Bean、Factory),那麼為了讓大家對這兩個概念有更清楚的了解,我們就來說一下他們兩個之間的區別
從他們的尾部單詞可知,FactoryBean是一個Bean,而BeanFactory是我們所說的容器,具有管理Bean的功能,前面我們已經講述過BeanFactory相關的功能,這裡我們不在過多的贅述,他倆的直觀區別就是一個是bean,一個是管理bean的容器
FactoryBean是一種特殊的Bean,FactoryBean介面定義了三個方法
public interface FactoryBean<T> { String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType"; @Nullable //返回有FactoryBean創建的Bean實例,如果isSingleton()返回true,則該實例會放到Spring容器的單實例快取池中。 T getObject() throws Exception; @Nullable //返回FactoryBean創建Bean的類型。 Class<?> getObjectType(); //確定由FactoryBean創建Bean的作用域是singleton還是prototype. default boolean isSingleton() { return true; } }
一般,我們都會通過實現Spring內部中的FactoryBean介面去創建一個自定義的factorybean
@Component public class FactoryBeanTest implements FactoryBean { @Override public Object getObject() throws Exception { return new ObjectBean(); } @Override public Class<?> getObjectType() { return ObjectBean.class; } }
package com.beans; public class ObjectBean { }
然後再在配置類中去獲取在getObject()方法中生成的ObjectBean對象
@ComponentScan("com.beans") public class mainT { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(mainT.class); System.out.println(context.getBean("factoryBeanTest")); System.out.println(context.getBean("factoryBeanTest")); System.out.println(context.getBean("factoryBeanTest")); //System.out.println(context.getBean("&factoryBeanTest")); } }
在這裡提出一個疑問:上述獲得的三個Bean是否是同一個?
答案 : 是同一個 ,因為FactoryBean中有一個默認的方法,是否是單例,默認為true,如果想得到非單例,可以重寫這個默認方法
default boolean isSingleton() { return true; }
即默認是單例的。
在提出一個疑問?上述4個Bean得到的是否是同一個類
答案:不是
System.out.println(context.getBean("factoryBeanTest")); System.out.println(context.getBean("factoryBeanTest")); System.out.println(context.getBean("factoryBeanTest")); //com.beans.ObjectBean@77f80c04 //com.beans.ObjectBean@77f80c04 //com.beans.ObjectBean@77f80c04 System.out.println(context.getBean("&factoryBeanTest")); //com.beans.FactoryBeanTest@1dac5ef
上面的注釋是每一個輸出語句輸出的結果,可以發現上方三個beanName沒有加&號的得到的bean是在FactoryBean中getObject方法new的類,而加了&符號的得到的是FactoryBean自身。
所以當你需要得到FactoryBean自身的話,在getBean的時候要在BeanName前加上一個或多個&即可。
那麼Spring如何去處理這個名字呢,我們可以看一下Spring中的源碼
//返回BeanName,去掉FatoryBean的&前綴,並且把name當作別名去aliasMap中尋找原始的beanName protected String transformedBeanName(String name) { return canonicalName(BeanFactoryUtils.transformedBeanName(name)); } public static String transformedBeanName(String name) { Assert.notNull(name, "'name' must not be null"); if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { return name; } //如果BeanName以&開頭,截取&後的beanname,並且把截取前後的name存儲到transformedBeanNameCache中 return transformedBeanNameCache.computeIfAbsent(name, beanName -> { do { beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); } while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)); return beanName; }); }
public String canonicalName(String name) { String canonicalName = name; // Handle aliasing... String resolvedName; do { //去找原始beanName,aliasMap:{別名:原始名} resolvedName = this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while (resolvedName != null); //如果通過別名找到原始beanName,則返回找出的原始beanName,如果沒有找到,則返回傳進來的BeanName return canonicalName; }
上述就是Spring處理這個beanName的方法,如果對上面程式碼有疑問或者不接,可以看作者做得一個流程圖,來幫助您加深記憶,更容易理解
這裡要說一下,Spring在getbean之前也就是在啟動的時候就會把FactoryBeanTest都載入到的BeanFactory中的單例池中,但沒有載入ObjectBean。
那麼除了FactoryBean以外還可以通過什麼來new一個對象而得到一個bean呢
就是@Bean註解,如下面例子所示:
@Configuration public class mainConfiguration { @Bean public ObjectBean getObjectBean(){ return new ObjectBean(); } }
那麼可以通過@Bean註解以一個相同的方法來得到一個Bean,為什麼還需要FactoryBean來定義一個Bean呢?因為當一個類繼承了FactoryBean之後,它還可以繼承其他的類和介面,起到一個拓展的作用。
public class FactoryBeanTest implements FactoryBean, BeanFactoryPostProcessor...
那麼在getBean方法中是如何去判斷這個Bean是不是一個FactoryBean以及如何載入getObject()方法中取到得對象為bean得呢
我們一同來看一下getBean()方法的源碼,只需要看前半部分即可
protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { //返回BeanName,去掉FatoryBean的&前綴,並且把name當作別名去aliasMap中尋找原始的beanName String beanName = transformedBeanName(name); Object beanInstance; // 根據beanName從單例池中獲取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 + "'"); } } //判斷sharedInstance是不是FactoryBean beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null); } // else { // // Fail if we're already creating this bean instance: // // We're assumably within a circular reference. // if (isPrototypeCurrentlyInCreation(beanName)) { // throw new BeanCurrentlyInCreationException(beanName); // } // // // Check if bean definition exists in this factory. // BeanFactory parentBeanFactory = getParentBeanFactory(); // if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // // Not found -> check parent. // String nameToLookup = originalBeanName(name); // if (parentBeanFactory instanceof AbstractBeanFactory) { // return ((AbstractBeanFactory) parentBeanFactory).doGetBean( // nameToLookup, requiredType, args, typeCheckOnly); // } // else if (args != null) { // // Delegation to parent with explicit args. // return (T) parentBeanFactory.getBean(nameToLookup, args); // } // else if (requiredType != null) { // // No args -> delegate to standard getBean method. // return parentBeanFactory.getBean(nameToLookup, requiredType); // } // else { // return (T) parentBeanFactory.getBean(nameToLookup); // } // } // //父子容器都沒有才去創建 // if (!typeCheckOnly) { // markBeanAsCreated(beanName); // } // // StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate") // .tag("beanName", name); // try { // if (requiredType != null) { // beanCreation.tag("beanType", requiredType::toString); // } // RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // checkMergedBeanDefinition(mbd, beanName, args); // // // Guarantee initialization of beans that the current bean depends on. // String[] dependsOn = mbd.getDependsOn(); // if (dependsOn != null) { // for (String dep : dependsOn) { // //判斷beanName是不是也被dep依賴了,如果是,就是相互依賴 // if (isDependent(beanName, dep)) { // throw new BeanCreationException(mbd.getResourceDescription(), beanName, // "Circular depends-on relationship between '" + beanName + "' and '" + //dep + "'"); // } // //載入依賴的bean // //存在在兩個map中 // //1、dependentBeanMap ,key為dep,value是一個LinkedHashSet,表示dep被哪些bean依賴了 // //2、dependenciesForBeanMap key為beanName,value是一個LinkedHashSet,表示beanName依賴了哪些bean // registerDependentBean(dep, beanName); // try { // //先去生成所依賴的bean // getBean(dep); // } // catch (NoSuchBeanDefinitionException ex) { // throw new BeanCreationException(mbd.getResourceDescription(), beanName, // "'" + beanName + "' depends on missing bean '" + dep + "'", ex); // } // } // } // // // Create bean instance. // if (mbd.isSingleton()) { // sharedInstance = getSingleton(beanName, () -> { // try { // return createBean(beanName, mbd, args); // } // catch (BeansException ex) { // // Explicitly remove instance from singleton cache: It might have been put there // // eagerly by the creation process, to allow for circular reference resolution. // // Also remove any beans that received a temporary reference to the bean. // destroySingleton(beanName); // throw ex; // } // }); // //sharedInstance可能是一個FactoryBean,所以需要單獨再去factoryBeanObjectCache中去獲取對應的對象 // beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); // } // // else if (mbd.isPrototype()) { // // It's a prototype -> create a new instance. // Object prototypeInstance = null; // try { // beforePrototypeCreation(beanName); // prototypeInstance = createBean(beanName, mbd, args); // } // finally { // afterPrototypeCreation(beanName); // } // beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); // } // //其他的scope request,session // else { // String scopeName = mbd.getScope(); // if (!StringUtils.hasLength(scopeName)) { // throw new IllegalStateException("No scope name defined for bean ´" + beanName + //"'"); // } // Scope scope = this.scopes.get(scopeName); // if (scope == null) { // throw new IllegalStateException("No Scope registered for scope name '" + scopeName + //"'"); // } // try { // Object scopedInstance = scope.get(beanName, () -> { // beforePrototypeCreation(beanName); // try { // return createBean(beanName, mbd, args); // } // finally { // afterPrototypeCreation(beanName); // } // }); // beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); // } // catch (IllegalStateException ex) { // throw new ScopeNotActiveException(beanName, scopeName, ex); // } // } // } // catch (BeansException ex) { // beanCreation.tag("exception", ex.getClass().toString()); // beanCreation.tag("message", String.valueOf(ex.getMessage())); // cleanupAfterBeanCreationFailure(beanName); // throw ex; // } // finally { // beanCreation.end(); // } // } // // return adaptBeanInstance(name, beanInstance, requiredType); // }
/** * @param beanInstance 從單例池中獲取到的bean * @param name 原始name(沒有經過任何處理,比如,沒有去掉&符號) * @param beanName 經過轉換後的name(例如:去掉了&符號) * @param mbd null * @return */ 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. //如果是&FactoryBean,那麼直接返回單例池中的對象,這裡就是判斷原始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. // 如果從單例池中的拿出來的Bean沒有繼承FactoryBean且beanName沒有以&開頭,則認為是普通bean,直接返回 if (!(beanInstance instanceof FactoryBean)) { return beanInstance; } // 如果beanInstance是FactoryBean且BeanName是以&開頭的 Object object = null; if (mbd != null) { mbd.isFactoryBean = true; } else { //首先去快取中通過BeanName獲取getObject方法得到的bean(這是為單例準備的) object = getCachedObjectForFactoryBean(beanName); } //從factoryBeanObjectCache中沒有拿到則進行創建 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)) { //獲取合併後beanDefinition mbd = getMergedLocalBeanDefinition(beanName); } boolean synthetic = (mbd != null && mbd.isSynthetic()); //調用getObject方法得到對象並放入factoryBeanObjectCache中 object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; }
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) { //調用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); 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 { //調用BeanPostProcessor執行初始化後的邏輯,主要就是進行AOP object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", ex); } finally { afterSingletonCreation(beanName); } } //如果是單例的,存入factoryBeanObjectCache中 //{工廠bean的名(沒有&符號):getObject()方法中new的新對象} if (containsSingleton(beanName)) { this.factoryBeanObjectCache.put(beanName, object); } } } return object; } } //當FactoryBean不是單例的情況下 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; } }
下面是一個流程圖,幫您加深印象以及能夠更好得了解上面得過程
總結:
1、什麼是FactoryBean
FactoryBean本質上是一個Bean,但他是一個特殊的Bean,而是一個能夠生產和修飾對象生成的工廠Bean。
2、FactoryBean與BeanFactory的區別
如1所說,FactoryBean本質上是一個Bean,但他比較特殊,它是可以生產和修飾對象生成的工廠Bean。
BeanFactory本質上是一個容器,所有Bean都是由BeanFactory來管理的,BeanFactory是一個介面,提供了IOC容器應遵守的最基本的介面,他的核心實現類是DefaultListableBeanFactory。
3、FactoryBean生產的Bean默認是單例的還是多例的
默認是單例的,可以重寫它的isSingleton()方法,修改返回值為false即可變為多例
4、如何獲得FactoryBean本身這個Bean
可以通過在beanName前加上一個或多個&符號來獲取
例如:getBean(“&FactoryBean的名字”)