spring IoC (四)FactoryBean
在Bean实例化过程中FactoryBean的处理过程
AbstractBeanFactory.getBean--->doGetBean--->getObjectForBeanInstance--->
FactoryBeanRegistrySupport.getObjectFromFactoryBean--->doGetObjectFromFactoryBean
1 protected Object getObjectForBeanInstance( 2 Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { 3 4 // Don't let calling code try to dereference the factory if the bean isn't a factory. 5 if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) { 6 throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); 7 } 8 9 // Now we have the bean instance, which may be a normal bean or a FactoryBean. 10 // If it's a FactoryBean, we use it to create a bean instance, unless the 11 // caller actually wants a reference to the factory. 12 if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { 13 return beanInstance; 14 } 15 16 Object object = null; 17 if (mbd == null) { 18 object = getCachedObjectForFactoryBean(beanName); 19 } 20 if (object == null) { 21 // Return bean instance from factory. 22 FactoryBean<?> factory = (FactoryBean<?>) beanInstance; 23 // Caches object obtained from FactoryBean if it is a singleton. 24 if (mbd == null && containsBeanDefinition(beanName)) { 25 mbd = getMergedLocalBeanDefinition(beanName); 26 } 27 boolean synthetic = (mbd != null && mbd.isSynthetic()); 28 object = getObjectFromFactoryBean(factory, beanName, !synthetic); 29 } 30 return object; 31 }
FactoryBeanRegistrySupport.getObjectFromFactoryBean
1 protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { 2 if (factory.isSingleton() && containsSingleton(beanName)) { 3 synchronized (getSingletonMutex()) { 4 Object object = this.factoryBeanObjectCache.get(beanName); 5 if (object == null) { 6 object = doGetObjectFromFactoryBean(factory, beanName); 7 // Only post-process and store if not put there already during getObject() call above 8 // (e.g. because of circular reference processing triggered by custom getBean calls) 9 Object alreadyThere = this.factoryBeanObjectCache.get(beanName); 10 if (alreadyThere != null) { 11 object = alreadyThere; 12 } 13 else { 14 if (object != null && shouldPostProcess) { 15 try { 16 object = postProcessObjectFromFactoryBean(object, beanName); 17 } 18 catch (Throwable ex) { 19 throw new BeanCreationException(beanName, 20 "Post-processing of FactoryBean's singleton object failed", ex); 21 } 22 } 23 this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT)); 24 } 25 } 26 return (object != NULL_OBJECT ? object : null); 27 } 28 } 29 else { 30 Object object = doGetObjectFromFactoryBean(factory, beanName); 31 if (object != null && shouldPostProcess) { 32 try { 33 object = postProcessObjectFromFactoryBean(object, beanName); 34 } 35 catch (Throwable ex) { 36 throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); 37 } 38 } 39 return object; 40 } 41 }
doGetObjectFromFactoryBean
1 private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) 2 throws BeanCreationException { 3 4 Object object; 5 try { 6 if (System.getSecurityManager() != null) { 7 AccessControlContext acc = getAccessControlContext(); 8 try { 9 object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { 10 public Object run() throws Exception { 11 return factory.getObject(); 12 } 13 }, acc); 14 } 15 catch (PrivilegedActionException pae) { 16 throw pae.getException(); 17 } 18 } 19 else { 20 object = factory.getObject(); 21 } 22 } 23 catch (FactoryBeanNotInitializedException ex) { 24 throw new BeanCurrentlyInCreationException(beanName, ex.toString()); 25 } 26 catch (Throwable ex) { 27 throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex); 28 } 29 30 // Do not accept a null value for a FactoryBean that's not fully 31 // initialized yet: Many FactoryBeans just return null then. 32 if (object == null && isSingletonCurrentlyInCreation(beanName)) { 33 throw new BeanCurrentlyInCreationException( 34 beanName, "FactoryBean which is currently in creation returned null from getObject"); 35 } 36 return object; 37 }