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
原文:https://www.cnblogs.com/makai/p/12246206.html