Spring 中有兩種類型的Bean,一種是普通Bean,另一種是工廠Bean 即 FactoryBean。FactoryBean跟普通Bean不同,其返回的對象不是指定類的一個實例,而是該FactoryBean的getObject方法所返回的對象。創建出來的對象是否屬於單例由isSingleton中的返回決定。
一般情況下,Spring通過反射機制利用<bean>的class屬性指定實現類實例化Bean,在某些情況下,實例化Bean過程比較復雜,如果按照傳統的方式,則需要在<bean>中提供大量的配置信息。配置方式的靈活性是受限的,這時采用編碼的方式可能會得到一個簡單的方案。Spring為此提供了一個org.springframework.bean.factory.FactoryBean的工廠類接口,用戶可以通過實現該接口定制實例化Bean的邏輯。FactoryBean接口對於Spring框架來說占用重要的地位,Spring自身就提供了70多個FactoryBean的實現。它們隱藏了實例化一些復雜Bean的細節,給上層應用帶來了便利。從Spring3.0開始,FactoryBean開始支持泛型,即接口聲明改為FactoryBean<T>的形式
以Bean結尾,表示它是一個Bean,不同於普通Bean的是:它是實現了FactoryBean<T>接口的Bean,根據該Bean的ID從BeanFactory中獲取的實際上是FactoryBean的getObject()返回的對象,而不是FactoryBean本身,如果要獲取FactoryBean對象,請在id前面加一個&符號來獲取。
FactoryBean接口定義
1 package org.springframework.beans.factory; 2 3 public interface FactoryBean<T> { 4 T getObject() throws Exception; 5 6 Class<?> getObjectType(); 7 8 boolean isSingleton(); 9 }
應用場景
FactoryBean 通常是用來創建比較復雜的bean,一般的bean 直接用xml配置即可,但如果一個bean的創建過程中涉及到很多其他的bean 和復雜的邏輯,用xml配置比較困難,這時可以考慮用FactoryBean。
很多開源項目在集成Spring 時都使用到FactoryBean,比如 MyBatis3 提供 mybatis-spring項目中的 org.mybatis.spring.SqlSessionFactoryBean:
1 <!-- spring和MyBatis整合,不需要mybatis的配置映射文件 --> 2 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 3 <property name="dataSource" ref="dataSource"/> 4 <!-- 自動掃描mapping.xml文件 --> 5 <property name="mapperLocations" value="classpath:mapper/*.xml"></property> 6 </bean>
1 public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> { 2 private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class); 3 ... 4 public SqlSessionFactory getObject() throws Exception { 5 if (this.sqlSessionFactory == null) { 6 this.afterPropertiesSet(); 7 } 8 9 return this.sqlSessionFactory; 10 } 11 ... 12 }
下面看一下具體的源碼:
AbstractBeanFactory通過getBean向IoC容器獲取被管理的Bean:
AbstractBeanFactory的getBean相關方法的源碼如下:
1 protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { 2 final String beanName = this.transformedBeanName(name); 3 Object sharedInstance = this.getSingleton(beanName); 4 Object bean; 5 if (sharedInstance != null && args == null) { 6 if (this.logger.isDebugEnabled()) { 7 if (this.isSingletonCurrentlyInCreation(beanName)) { 8 this.logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); 9 } else { 10 this.logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); 11 } 12 } 13 14 bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null); 15 } else { 16 if (this.isPrototypeCurrentlyInCreation(beanName)) { 17 throw new BeanCurrentlyInCreationException(beanName); 18 } 19 20 BeanFactory parentBeanFactory = this.getParentBeanFactory(); 21 if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) { 22 String nameToLookup = this.originalBeanName(name); 23 if (args != null) { 24 return parentBeanFactory.getBean(nameToLookup, args); 25 } 26 27 return parentBeanFactory.getBean(nameToLookup, requiredType); 28 } 29 30 if (!typeCheckOnly) { 31 this.markBeanAsCreated(beanName); 32 } 33 34 try { 35 final RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName); 36 this.checkMergedBeanDefinition(mbd, beanName, args); 37 String[] dependsOn = mbd.getDependsOn(); 38 String[] var11; 39 if (dependsOn != null) { 40 var11 = dependsOn; 41 int var12 = dependsOn.length; 42 43 for(int var13 = 0; var13 < var12; ++var13) { 44 String dependsOnBean = var11[var13]; 45 if (this.isDependent(beanName, dependsOnBean)) { 46 throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'"); 47 } 48 49 this.registerDependentBean(dependsOnBean, beanName); 50 this.getBean(dependsOnBean); 51 } 52 } 53 54 if (mbd.isSingleton()) { 55 sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() { 56 public Object getObject() throws BeansException { 57 try { 58 return AbstractBeanFactory.this.createBean(beanName, mbd, args); 59 } catch (BeansException var2) { 60 AbstractBeanFactory.this.destroySingleton(beanName); 61 throw var2; 62 } 63 } 64 }); 65 bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 66 } else if (mbd.isPrototype()) { 67 var11 = null; 68 69 Object prototypeInstance; 70 try { 71 this.beforePrototypeCreation(beanName); 72 prototypeInstance = this.createBean(beanName, mbd, args); 73 } finally { 74 this.afterPrototypeCreation(beanName); 75 } 76 77 bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 78 } else { 79 String scopeName = mbd.getScope(); 80 Scope scope = (Scope)this.scopes.get(scopeName); 81 if (scope == null) { 82 throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); 83 } 84 85 try { 86 Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() { 87 public Object getObject() throws BeansException { 88 AbstractBeanFactory.this.beforePrototypeCreation(beanName); 89 90 Object var1; 91 try { 92 var1 = AbstractBeanFactory.this.createBean(beanName, mbd, args); 93 } finally { 94 AbstractBeanFactory.this.afterPrototypeCreation(beanName); 95 } 96 97 return var1; 98 } 99 }); 100 bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd); 101 } catch (IllegalStateException var21) { 102 throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", var21); 103 } 104 } 105 } catch (BeansException var23) { 106 this.cleanupAfterBeanCreationFailure(beanName); 107 throw var23; 108 } 109 } 110 111 if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) { 112 try { 113 return this.getTypeConverter().convertIfNecessary(bean, requiredType); 114 } catch (TypeMismatchException var22) { 115 if (this.logger.isDebugEnabled()) { 116 this.logger.debug("Failed to convert bean '" + name + "' to required type [" + ClassUtils.getQualifiedName(requiredType) + "]", var22); 117 } 118 119 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); 120 } 121 } else { 122 return bean; 123 } 124 }
我們可以看到,無論是直接取單例的bean,還是創建單例、多例、自定義生命周期的bean,都會經過bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);這個方法,我們現在就來看看這里到底是做了什么。
1 protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { 2 if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) { 3 throw new BeanIsNotAFactoryException(this.transformedBeanName(name), beanInstance.getClass()); 4 } else if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) { 5 Object object = null; 6 if (mbd == null) { 7 object = this.getCachedObjectForFactoryBean(beanName); 8 } 9 10 if (object == null) { 11 FactoryBean<?> factory = (FactoryBean)beanInstance; 12 if (mbd == null && this.containsBeanDefinition(beanName)) { 13 mbd = this.getMergedLocalBeanDefinition(beanName); 14 } 15 16 boolean synthetic = mbd != null && mbd.isSynthetic(); 17 object = this.getObjectFromFactoryBean(factory, beanName, !synthetic); 18 } 19 20 return object; 21 } else { 22 return beanInstance; 23 } 24 }
這里有必要單獨說一下解引用:
Dereference(解引用):一個在C/C++中應用的比較多術語,在C++中,“*”是解引用符號,“&”是引用符號。
解引用:變量所指向的是所引用對象的本身數據,而不是對象的內存地址。
上面的代碼可以看到,對於大多數bean的getBean,一般走到第二步就返回了,也就是說我們創建的Bean對象就是想要的bean,但對於FactoryBean的創建,如果是對內存地址的引用,那么取到的是它生產的bean,而不是它本身。所以我們繼續看怎么取到生產的對象的:
FactoryBeanRegistrySupport類的getObjectFromFactoryBean方法
1 protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { 2 if (factory.isSingleton() && this.containsSingleton(beanName)) { 3 synchronized(this.getSingletonMutex()) { 4 Object object = this.factoryBeanObjectCache.get(beanName); 5 if (object == null) { 6 object = this.doGetObjectFromFactoryBean(factory, beanName); 7 Object alreadyThere = this.factoryBeanObjectCache.get(beanName); 8 if (alreadyThere != null) { 9 object = alreadyThere; 10 } else { 11 if (object != null && shouldPostProcess) { 12 try { 13 object = this.postProcessObjectFromFactoryBean(object, beanName); 14 } catch (Throwable var9) { 15 throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", var9); 16 } 17 } 18 19 this.factoryBeanObjectCache.put(beanName, object != null ? object : NULL_OBJECT); 20 } 21 } 22 23 return object != NULL_OBJECT ? object : null; 24 } 25 } else { 26 Object object = this.doGetObjectFromFactoryBean(factory, beanName); 27 if (object != null && shouldPostProcess) { 28 try { 29 object = this.postProcessObjectFromFactoryBean(object, beanName); 30 } catch (Throwable var11) { 31 throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", var11); 32 } 33 } 34 35 return object; 36 } 37 } 38 doGetObjectFromFactoryBean: 39 private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, String beanName) throws BeanCreationException { 40 Object object; 41 try { 42 if (System.getSecurityManager() != null) { 43 AccessControlContext acc = this.getAccessControlContext(); 44 45 try { 46 object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { 47 public Object run() throws Exception { 48 return factory.getObject(); 49 } 50 }, acc); 51 } catch (PrivilegedActionException var6) { 52 throw var6.getException(); 53 } 54 } else { 55 object = factory.getObject(); 56 } 57 } catch (FactoryBeanNotInitializedException var7) { 58 throw new BeanCurrentlyInCreationException(beanName, var7.toString()); 59 } catch (Throwable var8) { 60 throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", var8); 61 } 62 63 if (object == null && this.isSingletonCurrentlyInCreation(beanName)) { 64 throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject"); 65 } else { 66 return object; 67 } 68 }
第一個方法就是區分單例還是多例,第二個方法是真真的調用getObject的方法獲得FactoryBean生產的對象。從代碼中可以看到,具體產生Bean的地方時這個getObject方法,Spring為這個FactoryBean提供了70多個實現,比如Poxy、JDNI、RMI等等。
————————————————
版權聲明:本文為CSDN博主「liuhmmjj」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u014082714/article/details/81166648