【spring源码系列】之【FactoryBean类型的接口】

1.概述

目前我们知道,spring创建bean有多种方式,比如xml方式创建,比如@Component,@Service,@Controler,@Repository注解创建,比如@Autowired依赖注入创建,后续还有通过springboot方式的配置注解@Configuration与@Bean方式结合创建,这里不一一介绍,等分析spring boot源码的时候再做总结。

就spring本身,提供了一种接口方式创建bean,就是本节要讨论的通过FactoryBean接口方式创建。

2.实例

FactoryBean接口的实现类FactoryBeanDemo:

package com.wzj.FactoryBean;  import org.springframework.beans.factory.FactoryBean; import org.springframework.stereotype.Service;  @Service public class FactoryBeanDemo implements FactoryBean {      @Override     public Object getObject() throws Exception {         return new FactoryB();     }      @Override     public Class<?> getObjectType() {         return FactoryB.class;     } } 

通过FactoryBean实现类,完成自定义类FactoryB的实例化,FactoryB:

package com.wzj.FactoryBean;  import lombok.Data;  @Data public class FactoryB {     private String name = "wzj"; } 

测试类:

public class TestSpring {      @Autowired     private ApplicationContext applicationContext;      @Test     public void testFactoryBean() {         ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");         FactoryB factoryB = (FactoryB)applicationContext.getBean("factoryBeanDemo");         System.out.println(factoryB);          FactoryBeanDemo factoryBeanDemo = (FactoryBeanDemo)applicationContext.getBean("&factoryBeanDemo");         System.out.println(factoryBeanDemo);     } 

测试结果:
【spring源码系列】之【FactoryBean类型的接口】

可以看出,当获取名称为factoryBeanDemo的实例时,得到的是getObject()方法里创建的FactoryB类型的对象,而获取加前缀&factoryBeanDemo的实例时,得到的是FactoryBeanDemo本身的实例。

3.源码

step1: FactoryBean 接口的调用入口在实例化和 IOC/DI 做完后,就会调用 FactoryBean 类型的接口如下图所示

				// Create bean instance. 				// 创建bean实例 				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; 						} 					}); 					// FactoryBean的调用入口 					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 				} 

step2: 如果要获取到 FactoryBean 类本身,就必须加上&符号,比如 beanFactory.getBean("&beanName") ,如下:

	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不为空,且以前缀&打头,直接返回bean本身 		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. 		if (!(beanInstance instanceof FactoryBean)) { 			return beanInstance; 		}  		 
	public static boolean isFactoryDereference(@Nullable String name) { 		return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)); 	} 
	String FACTORY_BEAN_PREFIX = "&"; 

stet3: BeanFactory.getBean("beanName")只能获取到 getObject()方法返回的实例。getObject 方法返回的实例会有单独的缓存存储,跟其他实例不是同一个缓存,对应的缓存是:factoryBeanObjectCache

                // 如果是不是以前缀&打头,并且是FactoryBean类型的 		Object object = null; 		if (mbd != null) { 			mbd.isFactoryBean = true; 		} 		else { 			// 从缓存里拿FactoryBean实例 			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; 	} 
	protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { 		if (factory.isSingleton() && containsSingleton(beanName)) { 			synchronized (getSingletonMutex()) { 				// 先从缓存factoryBeanObjectCache取 				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 { 								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; 			} 		}                 ...... 

小结:具体代码参考 getSingleton 方法之后 getObjectForBeanInstance

  • 如果bean实例不是 FactoryBean 类型的或者 name 以&开始的则直接返回实例。
  • 如果bean是 FacotyBean 并且不是以&开头, 会通过方法doGetObjectFromFactoryBean 调用FactoryBean 内部继承实现的 getObject 方法,并且判断一级缓存中如果存在该 bean 实例把实例缓存到factoryBeanObjectCache 对应的 map 中,这个是单独缓存 FactoryBean 类型实例的 map。

4.总结

灵活创建所需实例对象的时候,通过实现FactoryBean接口的getObject方法定义实例化过程。

比如MyBatis提供mybatis-spring项目中的 org.mybatis.spring.SqlSessionFactoryBean

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> { 	// ...省略其他代码 	 	public SqlSessionFactory getObject() throws Exception { 	if (this.sqlSessionFactory == null) { 	  afterPropertiesSet(); 	}  	return this.sqlSessionFactory; 	} }  

sqlSessionFactory是SqlSessionFactoryBean的一个属性,它的赋值是在通过回调afterPropertiesSet()方法进行的。 因为SqlSessionFactoryBean实现了InitializingBean接口,所以在Spring初始化Bean的时候,能回调afterPropertiesSet()方法。

public void afterPropertiesSet() throws Exception {     // buildSqlSessionFactory()方法会根据mybatis的配置进行初始化。 	this.sqlSessionFactory = buildSqlSessionFactory(); }  

在上面的afterPropertiesSet()方法中,buildSqlSessionFactory()方法会根据mybatis的配置,完成客户所需要的的sessionFactory的初始化。

发表评论

相关文章