Spring bean加载2--FactoryBean情况处理
Spring bean加载2--FactoryBean情况处理
在Spring bean加载过程中,每次bean实例在返回前都会调用getObjectForBeanInstance来处理FactoryBean的情况.
这边的FactoryBean,Spring设计用于新建复杂bean的,联想下GOF设计模式的创建型,一样的为了解决复杂的bean实例化过程.
其实这边的FactoryBean就是一个factory method[gof定义的意图:定义一个用于创建对象的接口,让子类决定实例化哪个类.Factory Method使一个类的实例化延迟到其子类].
这边的处理主要涉及3个方法,我们来看看3个方法各自的职责:
- getObjectForBeanInstance: 参数校验之类的准备工作
- getObjectFromFactoryBean: 单例时,确保实例是全局唯一的
- doGetObjectFromFactoryBean: 实实在在的实例化
参数校验之类的准备工作##
AbstractBeanFactory的getObjectForBeanInstance处理.
- 如果name制定要获取FactoryBean本身实例,而beanInstance却又不是FactoryBean,直接抛异常
- 如果不需要调用getObject实例化,直接返回实例
- 尝试从缓存中获取实例[FactoryBeanRegistrySupport负责]
- 准备beanDefinition,委托getObjectFromFactoryBean处理
单例时保障实例全局唯一##
FactoryBeanRegistrySupport的getObjectFromFactoryBean处理
FactoryBeanRegistrySupport负责FactoryBean相关的操作,并缓存FactoryBean的getObject实例化的bean.
- 判断factory是单例,同时已经new好了(后面需要调用getObject获取目标对象,这边需要factory已经实例化)
- 单例时,先尝试去缓存找;如果找不到或者不是单例,委托doGetObjectFromFactoryBean实例化一个
- 由于这样新建就没有机会调用BeanPostProcessor了,所以这边直接调用其postProcessAfterInitialization[职责职责职责,AbstractAutowireCapableBeanFactory干的]
- 缓冲得到的实例
实例化,干活的##
FactoryBeanRegistrySupport的doGetObjectFromFactoryBean处理
这边做的事很少,就是调用factoryBean的getObject,然后如果实例化得到的对象为空抛异常.
源码摘要##
AbstractBeanFactory
/**
* Get the object for the given bean instance, either the bean
* instance itself or its created object in case of a FactoryBean.
* 返回bean 实例的对象,可能是实例本身,也可能是FactoryBean新建的对象
* @param beanInstance the shared bean instance
* @param name name that may include factory dereference prefix
* @param beanName the canonical bean name
* @param mbd the merged bean definition
* @return the object to expose for the bean
*/
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// 如果想要获取FactoryBean本身,那么beanInstance必须是FactoryBean的实例
// 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());
}
// 如果instance不是FactoryBean实例,或者想要获取的就是FactoryBean实例,那么直接返回就好
// 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) {
// 缓存中没有对象,那么从头准备bean defition实例化一个
// 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;
}
FactoryBeanRegistrySupport
/**
* Obtain an object to expose from the given FactoryBean, if available
* in cached form. Quick check for minimal synchronization.
* 获取缓存的,通过FactoryBean暴露出来的对象
* @param beanName the name of the bean
* @return the object obtained from the FactoryBean,
* or {@code null} if not available
*/
protected Object getCachedObjectForFactoryBean(String beanName) {
Object object = this.factoryBeanObjectCache.get(beanName);
// 类似<重构>中Introduce NUll Object,只是这边的NULL_OBJECT是Object类型的,没有解决Martin说的"不需要询问对象类型,就可以直接调用行为的方法"
return (object != NULL_OBJECT ? object : null);
}
/**
* Obtain an object to expose from the given FactoryBean.
* @param factory the FactoryBean instance
* @param beanName the name of the bean
* @param shouldPostProcess whether the bean is subject to post-processing
* @return the object obtained from the FactoryBean
* @throws BeanCreationException if FactoryBean object creation failed
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
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) {
// 缓存中找不到,就自己干吧,实例化
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) {
try {
// 外面BeanPostProcessor作用在factory上,没有作用在实际想要的实例上,这边补一个
// 也就是说,BeanPostProcessor的postProcessBeforeInitialization不会作用在FactoryBean上
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
}
// 缓存
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;
}
}
/**
* Obtain an object to expose from the given FactoryBean.
* @param factory the FactoryBean instance
* @param beanName the name of the bean
* @return the object obtained from the FactoryBean
* @throws BeanCreationException if FactoryBean object creation failed
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
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;
}
/**
* Post-process the given object that has been obtained from the FactoryBean.
* The resulting object will get exposed for bean references.
* <p>The default implementation simply returns the given object as-is.
* Subclasses may override this, for example, to apply post-processors.
* @param object the object obtained from the FactoryBean.
* @param beanName the name of the bean
* @return the object to expose
* @throws org.springframework.beans.BeansException if any post-processing failed
*/
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
return object;
}
AbstractAutowireCapableBeanFactory
/**
* Applies the {@code postProcessAfterInitialization} callback of all
* registered BeanPostProcessors, giving them a chance to post-process the
* object obtained from FactoryBeans (for example, to auto-proxy them).
* @see #applyBeanPostProcessorsAfterInitialization
*/
@Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
Spring bean加载2--FactoryBean情况处理的更多相关文章
- 07.Spring Bean 加载 - BeanDefinitionReader
基本概念 BeanDefinitionReader ,该接口的作用就是加载 Bean. 在 Spring 中,Bean 一般来说都在配置文件中定义.而在配置的路径由在 web.xml 中定义.所以加载 ...
- Spring bean加载之1:BeanFactory和FactoryBean
BeanFactory BeanFactory:以Factory结尾,表示它是一个工厂类(接口),用于管理Bean的一个工厂.在Spring中,BeanFactory是IOC容器的核心接口,它的职责包 ...
- spring bean加载顺序指定方式之一
在某些情况下,我们在容器启动的时候做一些事情,举个例子,加载缓存等.. 此时我们会希望某个bean先被加载并执行其中的afterpropertiesset方法. 因为spring默认是通过contex ...
- Spring bean加载多个配置文件
除了写很简单的加载一个xml,加载多个的情况一直没用到,在公司里也不会由自己处理这个问题,现在需要用到了,就研究验证一下. 使用的案例还是上面的例子. 只有,将原来的beans.xml分成两个部分. ...
- spring bean 加载过程(spring)
以classpathXmlApplication为例 入口方法包含3个部分, public ClassPathXmlApplicationContext(String[] configLocation ...
- 【Spring源码分析】Bean加载流程概览
代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...
- 【Spring源码分析】Bean加载流程概览(转)
转载自:https://www.cnblogs.com/xrq730/p/6285358.html 代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. ...
- Spring源码分析:Bean加载流程概览及配置文件读取
很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事的都是Java Web的工作,对于程序员来说,一个Web项目用到Spring,只是配置一下配置文件而已 ...
- spring源码阅读笔记06:bean加载之准备创建bean
上文中我们学习了bean加载的整个过程,我们知道从spring容器中获取单例bean时会先从缓存尝试获取,如果缓存中不存在已经加载的单例bean就需要从头开始bean的创建,而bean的创建过程是非常 ...
随机推荐
- git命令图片
- libUpnp缓冲区溢出、拒绝服务等漏洞分析
该漏洞存在于UPnP™设备的便携式SDK中,也叫做 libupnp.这个库是用来实现媒体播放(DLAN)或者NAT地址转换(UPnP IGD).智能手机上的应用程序可用这些功能播放媒体文件或者利用用户 ...
- 迷你MVVM框架 avalonjs 学习教程13、模板引用
稍为复杂一点的网站都是多个前端工程师合作而成,因此分工是必需的.简单一点的分工就是一个人负责一个频道,某个页面是由一个人全部做的:但如果涉及到一个页面非常复杂,需要多个人同时动工呢?于是到模板的出场时 ...
- 常用类一一MATH类一一两个静态常量PI 和E,一些数学函数。
package test; public class MathTest { public static void main(String[] args) { System.out.println(Ma ...
- django中怎么使用mysql数据库的事务
Mysql数据库事务: 在进行后端业务开始操作修改数据库时,可能会涉及到多张表的数据修改,对这些数据的修改应该是一个整体事务,即要么一起成功,要么一起失败. Django中对于数据库的事务,默认每执行 ...
- CentOS 6.3安装配置supervisor进程管理工具
1. Supervisor是一个C/S系统,它可以在类unix操作系统让用户来监视和控制后台服务进程的数量,一个很重要的功能就是监控服务器的主要后台进程,并在出现问题是自动重启. 2. 根据服务器上的 ...
- padding-top和margin-top的区别
学习前端知识,对我们查找页面元素很有帮助,而且自己在原公司时,有参与一个QA系统,自己去设计了这个产品,出了原型图,同时设计了几个页面,希望通过做这个产品提高自己的技术,可是因为离职,所以计划搁浅了, ...
- switch_to_frame,切换frame框架
页面包含frame/iframe标签,需要先切换到该frame标签,再去定位属于这个frame的元素. 如果要再去定位其他frame的元素,需要回到该frame的上级,定位到要选择的frame,不 ...
- input radio 与label文字对齐
input{ vertical-align:middle; margin-bottom:2px; *margin-bottom:2px; } 原地址
- 通过dockerfile构建nginx
上次 利用命令行的形式来构建nginx服务, http://www.cnblogs.com/loveyouyou616/p/6806788.html 这次利用dockerfile文件来构建nginx服 ...