Spring 源码学习(4)—— bean的加载part 1
前面随笔中,结束了对配置文件的解析工作,以及将配置文件转换成对应的BeanDefinition存储在容器中。接下来就该进行bean的加载了。
public Object getBean(String name) throws BeansException {
return this.doGetBean(name, (Class)null, (Object[])null, false);
}
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = this.transformedBeanName(name);
Object sharedInstance = this.getSingleton(beanName);
Object bean;
if (sharedInstance != null && args == null) {
if (this.logger.isDebugEnabled()) {
if (this.isSingletonCurrentlyInCreation(beanName)) {
this.logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
} else {
this.logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
} bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
if (this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
} BeanFactory parentBeanFactory = this.getParentBeanFactory();
if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
String nameToLookup = this.originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
} if (args != null) {
return parentBeanFactory.getBean(nameToLookup, args);
} return parentBeanFactory.getBean(nameToLookup, requiredType);
} if (!typeCheckOnly) {
this.markBeanAsCreated(beanName);
} try {
RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
String[] var11;
if (dependsOn != null) {
var11 = dependsOn;
int var12 = dependsOn.length; for(int var13 = 0; var13 < var12; ++var13) {
String dep = var11[var13];
if (this.isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
} this.registerDependentBean(dep, beanName);
this.getBean(dep);
}
} if (mbd.isSingleton()) {
sharedInstance = this.getSingleton(beanName, () -> {
try {
return this.createBean(beanName, mbd, args);
} catch (BeansException var5) {
this.destroySingleton(beanName);
throw var5;
}
});
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
var11 = null; Object prototypeInstance;
try {
this.beforePrototypeCreation(beanName);
prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
} bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
String scopeName = mbd.getScope();
Scope 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, () -> {
this.beforePrototypeCreation(beanName); Object var4;
try {
var4 = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
} return var4;
});
bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException var21) {
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", var21);
}
}
} catch (BeansException var23) {
this.cleanupAfterBeanCreationFailure(beanName);
throw var23;
}
} if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = this.getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
} else {
return convertedBean;
}
} catch (TypeMismatchException var22) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", var22);
} throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
} else {
return bean;
}
}
在这段代码中,我们可以看出bean的加载经历了一个相当复杂的过程,并不是我们想象中简单的用bean的class属性通过反射的方式来实例化bean。其中涉及到方方面面的考虑,不得不佩服开发者缜密的思维。
对于bean加载的过程大致可以总结如下:
1、转换对应的beanName
String beanName = this.transformedBeanName(name);
protected String transformedBeanName(String name) {
return this.canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
这里的目的是通过name得到真正的beanName。
在BeanFactoryUtils.transformedBeanName()中将name前的‘&’符号去除。之前的随笔中有说到过,Spring除了可以通过我们常见的set注入和构造器注入的方式生成bean,还可以通过工厂方法来实例化bean。例如
<bean id="production" class="com.wuzhe.factory.MyBeanFactory"/>
这样通过beanFactory.getBean() 得到的bean就是通过MyBeanFactory实现FactoryBean的getObject()方法实例化而来的。
如果我们想要得到的MyFactoryBean本身这个bean的话,就需要在beanName前加上‘&’符号。例beanFactory.getBean("&production")
回到之前的代码中,处理完‘&’符号的name之后,在cannonicalName()方法里会遍历容器中aliasMap中维护的alia对应beanName的关系,得到真正的beanName
2、尝试从缓存中加载单例
Object sharedInstance = this.getSingleton(beanName);
@Nullable
public Object getSingleton(String beanName) {
return this.getSingleton(beanName, true);
} @Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
Map var4 = this.singletonObjects;
synchronized(this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
} return singletonObject;
}
因为单例的bean只需要初始化一次就足够了,因此在spring中,实例化过得单例bean都被存放在了缓存中,一旦后续再尝试获取该bean时,只需要从缓存中获取就足够了。
在读spring的源码时,经常被spring容器中的各种缓存搞的云里雾里,所以在解读之前先把我们将要用到的缓存名以及其用意列举一下。
singletonObjects:
维护了容器中已被实例化过的单例bean。通过beanName -> Object
factoryBeanObjectCache:
维护了容器中单例工厂FactoryBean对象getObject()得到的单例bean。通过beanName -> Object
singletonsCurrentlyInCreation:
存放了当前正在实例化中的单例bean beanName的集合。 Set<beanName>
earlySingletonObjects:
维护了容器中单例bean。通过beanName -> Object。和singletonObjects的区别是singletonObjects中存放的是已经实例化完成的bean,而在一个bean还未实例化完成时,spring就会通过对应的ObjectFactory的getObject()方法返回一个bean的引用并存放在earlySingletonObjects中,对于后面可能遇到的循环依赖有大用处。
singletonFactories:
维护了容器中还未生产过单例的ObjectFactory。通过beanName -> ObjectFactory。一旦某个ObjectFactory生产过bean,则这个bean会被放置到earlySingletonObjects中,并且这个ObjectFactory在singletonFactories中会被移除。
接下来结合getObjectForBeanInstance方法的代码一起看
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
if(BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(this.transformedBeanName(name), beanInstance.getClass());
} else if(beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
Object object = null;
if(mbd == null) {
object = this.getCachedObjectForFactoryBean(beanName);
} if(object == null) {
FactoryBean factory = (FactoryBean)beanInstance;
if(mbd == null && this.containsBeanDefinition(beanName)) {
mbd = this.getMergedLocalBeanDefinition(beanName);
} boolean synthetic = mbd != null && mbd.isSynthetic();
object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);
} return object;
} else {
return beanInstance;
}
}
我们将从缓存中获取对象的情况分成一下三种情况:
1、根据beanName在singletonObjects中能直接取到对象bean,且当前bean不是FactoryBean类,或者当前bean是FactoryBean类,但name中带有‘&’前缀:
说明这个获取得到的bean就是调用者想要获取的bean。这时只需要直接返回这个bean就可以了。
2、根据beanName在singletonObjects中能直接取到对象bean,但当前bean是FactoryBean类,且name中不带有‘&’前缀:
说明这个获取到的bean是工厂bean,调用者真正想要的是通过工厂生产出来的bean。
这时候spring并不会直接调用FactoryBean的getObject()获取bean,而是先从工厂生产的缓存factoryBeanObjectCache中查找。
protected Object getCachedObjectForFactoryBean(String beanName) {
Object object = this.factoryBeanObjectCache.get(beanName);
return object != NULL_OBJECT?object:null;
}
若找到了,则直接返回该bean。
如果没有找到,则先合并当前的beanDefinition和其父beanDefinition得到mbd。从而取到mbd的synthetic属性。这个属性标识这个bean是否是人工生成的
然后调用getObjectFromFactoryBean()方法
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if(factory.isSingleton() && this.containsSingleton(beanName)) {
synchronized(this.getSingletonMutex()) {
Object ex = this.factoryBeanObjectCache.get(beanName);
if(ex == null) {
ex = this.doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if(alreadyThere != null) {
ex = alreadyThere;
} else {
if(ex != null && shouldPostProcess) {
try {
ex = this.postProcessObjectFromFactoryBean(ex, beanName);
} catch (Throwable var9) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean\'s singleton object failed", var9);
}
} this.factoryBeanObjectCache.put(beanName, ex != null?ex:NULL_OBJECT);
}
} return ex != NULL_OBJECT?ex:null;
}
} else {
Object object = this.doGetObjectFromFactoryBean(factory, beanName);
if(object != null && shouldPostProcess) {
try {
object = this.postProcessObjectFromFactoryBean(object, beanName);
} catch (Throwable var11) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean\'s object failed", var11);
}
} return object;
}
}
如果这个factoryBean生成的不是单例的bean,则直接调用doGetObjectFromFactoryBean()方法
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
if(System.getSecurityManager() != null) {
AccessControlContext ex = this.getAccessControlContext(); try {
object = AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
return factory.getObject();
}
}, ex);
} catch (PrivilegedActionException var6) {
throw var6.getException();
}
} else {
object = factory.getObject();
}
} catch (FactoryBeanNotInitializedException var7) {
throw new BeanCurrentlyInCreationException(beanName, var7.toString());
} catch (Throwable var8) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", var8);
} if(object == null && this.isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject");
} else {
return object;
}
}
这里的System.getSecurityManager是获取系统的安全管理权限,在安全的情况下,调用了factoryBean的getObject()方法得到了bean。
如果这个factoryBean是单例工厂,则在通过doGetObjectFromFactoryBean()获取bean之后,将bean放置在了factoryBeanObjectCache缓存中。
这里的postProcessObjectFromFactoryBean方法是一个通过工厂生产bean的一个后处理器,关于后处理器在后续章节会详细了解,这里只需要知道在spring获取bean的规则中有一条:尽可能保证所有bean初始化后都会调用注册的BeanPostProcessor的postProcessAfterInitialization方法进行处理,在实际开发中,大可以针对此特性设计自己的业务逻辑。
3、根据beanName在singletonObjects中不能取到对象bean,但在singletonsCurrentlyInCreation中有此beanName:
说明这个bean正在被创建中,那么spring就会:
1)先尝试在earlySingletonObjects中查找bean的缓存,若找到了则直接返回。
2)如果还是没找到,就会在singletonFactories中查找这个beanName对应的ObjectFactory缓存,如果这时候还没找到,则需要走完创建bean的流程了,return 空。
3)如果找到了对应的ObjectFactory,则通过ObjectFactory的getObject()方法获取bean。并在将其放在earlySingletonObjects的缓存中。并在singletonFactories中移除次ObjectFactory。
这样通过缓存获取bean的过程就结束了。
Spring 源码学习(4)—— bean的加载part 1的更多相关文章
- spring源码学习之bean的加载(二)
这是接着上篇继续写bean的加载过程,好像是有点太多了,因为bean的加载过程是很复杂的,要处理的情况有很多,继续... 7.创建bean 常规的bean的创建时通过doCreateBean方法来实现 ...
- spring源码学习之bean的加载(一)
对XML文件的解析基本上已经大致的走了一遍,虽然没有能吸收多少,但是脑子中总是有些印象的,接下来看下spring中的bean的加载,这个比xml解析复杂的多.这个加载,在我们使用的时候基本上是:Bea ...
- spring源码学习之bean的加载(三)
接着二中的继续写,那个都超过1000行了,哈,需要重新写一个,要不太长了,我都看不下去了 7.4 初始化bean doCreateBean函数中有这样一行代码:这行代码中initializeBean函 ...
- Spring源码分析之Bean的加载流程
spring版本为4.3.6.RELEASE 不管是xml方式配置bean还是基于注解的形式,最终都会调用AbstractApplicationContext的refresh方法: @Override ...
- 【Spring源码分析】非懒加载的单例Bean初始化过程(下篇)
doCreateBean方法 上文[Spring源码分析]非懒加载的单例Bean初始化过程(上篇),分析了单例的Bean初始化流程,并跟踪代码进入了主流程,看到了Bean是如何被实例化出来的.先贴一下 ...
- 【Spring源码分析】非懒加载的单例Bean初始化前后的一些操作
前言 之前两篇文章[Spring源码分析]非懒加载的单例Bean初始化过程(上篇)和[Spring源码分析]非懒加载的单例Bean初始化过程(下篇)比较详细地分析了非懒加载的单例Bean的初始化过程, ...
- Spring源码分析:非懒加载的单例Bean初始化前后的一些操作
之前两篇文章Spring源码分析:非懒加载的单例Bean初始化过程(上)和Spring源码分析:非懒加载的单例Bean初始化过程(下)比较详细地分析了非懒加载的单例Bean的初始化过程,整个流程始于A ...
- Spring源码分析:非懒加载的单例Bean初始化过程(下)
上文Spring源码分析:非懒加载的单例Bean初始化过程(上),分析了单例的Bean初始化流程,并跟踪代码进入了主流程,看到了Bean是如何被实例化出来的.先贴一下AbstractAutowireC ...
- 【Spring源码分析】非懒加载的单例Bean初始化过程(上篇)
代码入口 上文[Spring源码分析]Bean加载流程概览,比较详细地分析了Spring上下文加载的代码入口,并且在AbstractApplicationContext的refresh方法中,点出了f ...
- Spring源码分析:非懒加载的单例Bean初始化过程(上)
上文[Spring源码分析]Bean加载流程概览,比较详细地分析了Spring上下文加载的代码入口,并且在AbstractApplicationContext的refresh方法中,点出了finish ...
随机推荐
- qrCode二维码字符串长度太多压缩的问题
昨天整微信的扫码支付时,用qrcode生成二维码,结果字符串太长而失败.今天发现利用pako压缩,可扫描后显示乱码,特记录一下. palo插件地址:https://github.com/nodeca/ ...
- 专题8:javascript中事件
一.事件流 1.1 事件冒泡 冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标的顺序逐一触发: 注意:各个浏览器在处理<html>标记级别的事件时顺序有出入,因此无论任何情况,都 ...
- 20190402Linux常用命令week1.1
Linux常用命令详解week1.1 基础命令:lsmanpwdcdmkdirechotouchcpmvrmrmdircatmorelessheadtailclearpoweroffreboot 命令 ...
- JavaScript case 条件语句
JavaScript case 条件语句 示例 switch(name){ case '1': age = 123; break; case '2' age = 456; break; default ...
- Mysql 集合链接查询
MySQL NULL 值处理 需求:我们已经知道MySQL使用 SQL SELECT 命令及 WHERE 子句来读取数据表中的数据,但是当提供的查询条件字段为 NULL 时,该命令可能就无法正常工作. ...
- Pandas截取列的一部分
以股票代码为例: 型式为:6位数字+"."+交易所代码,如600028.SH 如只需保留前6位: pattern = '(\w+)(?:.SZ|.SH)$' df['股票代码'] ...
- G711 G723 G729线路占多少带宽问题
G.711 G.711 也称为PCM(脉冲编码调制),是国际电信联盟订定出来的一套语音压缩标准,主要用于电话.它主要用脉冲编码调制对音频采样,采样率为8k每秒.它利用一个 64Kbps 未压缩 ...
- mvc 之 RouteConfig配置
//这里没有使用对用的指定参数 /Day_1:表示解决方案的名称,意思是默认找到该项目解决方案目录下的controllers进行匹配 routes.MapRoute( "Default&qu ...
- js 可以表示的最大值
, ); ; ; for (var i = START; i <= END; i++) { count++; } console.log(count); // A. 0 // B. 100 // ...
- 在pycharm中运行python程序
安装PyCharm 安装过程取决于您的操作系统: 在Windows上安装PyCharm 运行.exe您已下载的文件,并按照PyCharm安装向导的说明进行操作. 在macOS上安装PyCharm 打开 ...