FactoryBean使用方法
一般来说我们自己写的Bean在只继承自己的接口时创建Bean的过程是交给IOC容器来实现的。但是某些特殊情况如果单纯的交给Spring的IOC容器来实现会配置非常复杂有时甚至没办法实现。所以这种情况下Spring为我们提供了FactoryBean这个接口!这个接口有3个方法
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
-
getObject
方法用来获得一个Object对象当是单例时会将Object对象放入IOC容器缓存起来保证只会生成一个对象 -
isSingleton
判断是否是单例模式 -
getObjectType
返回对象的class
如果我们现在有个很复杂的对象需要实例,单纯的使用IOC容器帮我们创建比较复杂,所以需要自己写创建类的过程,这个时候就可以让你的类实现FactoryBean这个接口,然后自己实现创建对象的方法(getObject()
)方法。下面我从网上摘抄的一个简单的案例:在创建Car对象比较复杂,需要使用properties文件来生成,如果单纯使用IOC容器可能无法创建,所以需要自己写个CarFactoryBean
来创建Car对象 - 1.Car类的基本属性
public class Car {
private int maxSpeed ;
private String brand ;
private double price ;
//get/set方法
- 2.创建方式复杂所以需要自己创建Car对象,实现FactroyBean然后自己实现getObject方法
public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo ;
public Car getObject () throws Exception {
Car car = new Car () ;
String [] infos = carInfo .split ( "," ) ;
car.setBrand ( infos [ 0 ]) ;
car.setMaxSpeed ( Integer. valueOf ( infos [ 1 ])) ;
car.setPrice ( Double. valueOf ( infos [ 2 ])) ;
return car;
}
public Class<Car> getObjectType () {
return Car. class ;
}
public boolean isSingleton () {
return false ;
}
public String getCarInfo () {
return this . carInfo ;
}
// 接受逗号分割符设置属性信息
public void setCarInfo ( String carInfo ) {
this . carInfocarInfo = carInfo;
}
}
- 3.配置一个Car的Bean
<bean id="car" class="com.test.factorybean.CarFactoryBean" carInfo="超级跑车,400,2000000"/>
实现源码分析
前面基本使用方式已经知道了,再来看看Spring如何实现的。在使用getBean()
的时候可以找到最终调用的是AbstractBeanFactory.doGetBean()
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//1.如果是FactoryBean这种Bean都是以&开头。所以需要去掉&
//2.如果name的别名,则需要在SimpleAliasRegistry里面进行判断获取的真正的那么
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//从缓存中获取对象,避免重复创建
Object sharedInstance = getSingleton(beanName);
System.out.println(sharedInstance);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
} else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
/*这里 的 getObjectForBeanInstance 完成 的 是 FactoryBean 的 相关 处理,
以 取得 FactoryBean 的 生产 结果, BeanFactory 和 FactoryBean 的 区别 已经 在前面 讲过, 这个 过程 在后面 还会 详细 地 分析*/
bean = 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.
/*
这里 对 IoC 容器 中的 BeanDefintion 是否 存在 进行检查,
检查 是否 能在 当前 的 BeanFactory 中 取得 需要 的 Bean。
如果 在 当前 的 工厂 中 取 不到, 则 到 双亲 BeanFactory 中 去取;
如果 当前 的 双亲 工厂 取 不到, 那就 顺着 双亲 BeanFactory 链 一直 向上 查找*/
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
} else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
//通过beanName获得BeanDefinition对象 //这里 根据 Bean 的 名字 取得 BeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
//检查bean配置是否设置了depend-on属性。即实例A需要先实例B
//获取 当前 Bean 的 所有 依赖 Bean, 这样 会 触发 getBean 的 递归 调用, 直到 取 到 一个 没有
// 任何 依赖 的 Bean 为止
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
//Bean依赖别的bean,直接递归getBean即可
getBean(dep);
} catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
/*这里 通过 调用 createBean 方法 创建 Singleton bean 的 实例, 这里 有一个 回 调 函数 getObject,
会在 getSingleton 中 调用 ObjectFactory 的 createBean*/
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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;
}
}
});
bean = 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);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
String scopeName = mbd.getScope();
final 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, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
} finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException ex) {
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",
ex);
}
}
} catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
// 这里 对 创建 的 Bean 进行 类型 检查, 如果 没有 问题, 就 返回 这个 新 创建 的 Bean, 这个 Bean 已经 //是 包含 了 依赖 关系 的 Bean
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
} catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
通过上面的源码可以看到先通过IOC的 createBean(beanName, mbd, args);
最后都会走bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
这个方法就是FactoryBean调用getObject()方法的地方。看一下源码
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// 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) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
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;
}
分析一下上面的源码。首先判断当前获得的Bean是否是FactoryBean如果不是直接返回,如果是FactoryBean那么从缓存中获得,如果缓存中没有则创建也就是最后object = getObjectFromFactoryBean(factory, beanName, !synthetic);
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) {
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 (object != null && 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 != null ? object : NULL_OBJECT));
}
}
}
return (object != NULL_OBJECT ? object : null);
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
上面的源码会做一些前置后置处理。主要创建Object的方法是object = doGetObjectFromFactoryBean(factory, beanName);
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
return object;
}
看上面的源码object = factory.getObject();
最终都是通过你自己写的FactoryBean里面的getObject()来返回你需要的对象
框架中如何使用
在这节里面我们来使用一个框架来看看FactoryBean是如何在框架中使用的。Mybatis这个ORM框架现在在企业中使用已经很广泛了,所以我们来分析一下这个框架里面如何利用FactoryBean。在spring和Mybatis整合中有这样一个类
SqlSessionFactoryBean
作用是用来生成SqlSessionFactory
先看一下这个类的签名public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent>
类的签名继承了FactoryBean<SqlSessionFactory>
并且提供了泛型那么表示当时用getBean的使用会生成一个SqlSessionFactory
而我们知道在Mybatis里面生成SqlSessionFactory是很复杂的,需要定位资源,然后解析资源最后build生成SqlSessionFactory
这个过程是很复杂的单纯交给spring来处理比较麻烦,所以需要自己来实现这个创建的过程。所以Mybatis自己实现了getObject方法
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
当SqlSessionFactory
是空时,调用afterPropertiesSet();
这个方法是InitializingBean
接口里面的方法。
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
"Property 'configuration' and 'configLocation' can not specified with together");
this.sqlSessionFactory = buildSqlSessionFactory();
}
最后调用buildSqlSessionFactory();
这个方法会收集各种配置数据,最终调用Mybatis的sqlSessionFactoryBuilder.build(configuration);
来生成Object