【Spring源码学习】FactoryBean 类型的接口


前言

【Spring源码学习】Spring Bean实例化过程-创建Bean实例 一文中,实例在真正创建完成(完成了创建、依赖属性注入、初始化)后,会有FactoryBean的接口调用,我们先定位到这段代码来看看,本章也主要跟一下这个调用的流程。

//AbstractBeanFactory
protected <T> T doGetBean(
		String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
	// 获取一个beanName,处理两种情况,一个是前面说的 FactoryBean (前面带 '&'),
	// 一个是别名问题,因为这个方法是 getBean,获取 Bean 用的,你要是传一个别名进来,是完全可以的
	String beanName = transformedBeanName(name);
	Object bean;
	/*
	 * Description : 检查缓存中或者实例工厂中是否有对应的实例
	 * 因为在创建单例 bean的时候会存在依赖注入,而在创建依赖的时候为了避免循环依赖,
	 * spring创建bean的原则是:不等 bean 创建完成就将创建bean的 ObjectFactory 提早曝光,
	 *  换句话说,也就是将 ObjectFactory 加入到缓存中,一旦下一个bean创建的时候需要依赖上
	 *  一个bean则直接使用 ObjectFactory
	 *
	 *  第一次getSingleton(beanName)
	 */
	// Eagerly check singleton cache for manually registered singletons.
	Object sharedInstance = getSingleton(beanName);
	//如果缓存里面能拿到实例,但第一次缓存中是没有的,所以第一次不会进入这个if
	if (sharedInstance != null && args == null) {
		if (logger.isTraceEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		// 该方法是 FactoryBean 接口的调用入口
		// 如果是普通 Bean 的话,直接返回 sharedInstance(直接返回对象本身)
		// 如果是 FactoryBean 的话,返回它创建的那个实例对象(返回指定方法返回的实例)
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	//如果singletonObjects缓存里面没有,则走下来
	else {
		//如果是scope 是Prototype的,校验是否有出现循环依赖,如果有则直接报错
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
		// Check if bean definition exists in this factory.
		//检查一下这个 BeanDefinition 在容器中是否存在
		BeanFactory parentBeanFactory = getParentBeanFactory();
		
		//......省略部分代码
		
		//要开始创建bean了,分两种情况:一种是针对单例的(singleton),一种是针对多例的(prototype),一种是自定义scope的
		try {
			//父子BeanDefinition合并
			RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);
			//获取依赖对象属性,依赖对象要先实例化
			// Guarantee initialization of beans that the current bean depends on.
			String[] dependsOn = mbd.getDependsOn();
			
			//......省略部分代码
			
			//单例情况singleton,着重看,大部分是单例的情况
			// Create bean instance.
			if (mbd.isSingleton()) {
				sharedInstance = getSingleton(beanName, () -> {
					try {
						return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
						destroySingleton(beanName);
						throw ex;
					}
				});
				//该方法是FactoryBean接口的调用入口
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}
			//多例情况prototype
			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);
				}
				//该方法是FactoryBean接口的调用入口
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}
			// 如果不是 singleton 和 prototype 的话,需要委托给相应的实现类来处理
			else {
				String scopeName = mbd.getScope();
				if (!StringUtils.hasLength(scopeName)) {
					throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
				}
				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, () -> {
						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;
		}
	}

	//......省略部分代码
	
	return (T) bean;
}

bean = getObjectForBeanInstance()方法就是FactoryBean接口的调用入口了。而这个接口首次调用则是在创建完成一个可用的bean之后,也就是在下面这个代码里首次调用的(本章主要针对单例,其他多例、自定义scope类似)

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);
}

一、FactoryBean接口的调用

1.getObjectForBeanInstance()

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.
	//以&开头,针对本身就是FactoryBean的判断
	//如果要获取到FactoryBean 类本身,就必须加上”&”符号,比如beanFactory.getBean(“&beanName”),
	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.
	//如果实例不是FactoryBean类型的
	if (!(beanInstance instanceof FactoryBean)) {
		return beanInstance;
	}

	//如果代码能走下来,则说明 beanName不是以&开头,并且beanInstance是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;
}

这里有两种情况下的返回

  • 直接返回原对象:针对bean实例本身就是FactoryBean类型或者beanName是以&开头的情况
  • 返回factoryBean:beanName不是以&开头,并且beanInstance是FactoryBean类型的,这里又分情况:
    • 从factoryBeanObjectCache缓存中获取
    • 缓存中不存在该bean,则调用factory的getObject()方法,并且判断一级缓存中如果存在该bean 实例把实例缓存到factoryBeanObjectCache 对应的map 中,这个是单独缓存FactoryBean 类型实例的map

2.getObjectFromFactoryBean(),doGetObjectFromFactoryBean()

//FactoryBeanRegistrySupport
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
	//factory是单例且一级缓存中存在
	if (factory.isSingleton() && containsSingleton(beanName)) {
		synchronized (getSingletonMutex()) {
			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)) {
						//把实例缓存到factoryBeanObjectCache map中,这个是单独缓存FactoryBean类型实例的map
						this.factoryBeanObjectCache.put(beanName, object);
					}
				}
			}
			return object;
		}
	}
	else {
		Object object = doGetObjectFromFactoryBean(factory, beanName);
		if (shouldPostProcess) {
			try {
				object = postProcessObjectFromFactoryBean(object, beanName);
			}
			catch (Throwable ex) {
				throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
			}
		}
		return object;
	}
}

private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
	Object object;
	try {
		if (System.getSecurityManager() != null) {
			AccessControlContext acc = getAccessControlContext();
			try {
				object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
			//调用getObject方法
			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) {
		if (isSingletonCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(
					beanName, "FactoryBean which is currently in creation returned null from getObject");
		}
		object = new NullBean();
	}
	return object;
}

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

二、总结

  • FactoryBean 接口的首次调用入口在实例化、IOC/DI 以及初始化做完后,就会调用FactoryBean 类型的接口
  • 如果要获取到FactoryBean 类本身,就必须加上”&”符号,比如beanFactory.getBean(“&beanName”)
  • factoryBean有单独的缓存factoryBeanObjectCache,跟其他实例不是同一个

有关FactoryBean的作用和例子可以参考这位大佬写的例子-Spring 源码学习 FactoryBean


文章作者: Kezade
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Kezade !
评论
  目录