前面随笔中,结束了对配置文件的解析工作,以及将配置文件转换成对应的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的更多相关文章

  1. spring源码学习之bean的加载(二)

    这是接着上篇继续写bean的加载过程,好像是有点太多了,因为bean的加载过程是很复杂的,要处理的情况有很多,继续... 7.创建bean 常规的bean的创建时通过doCreateBean方法来实现 ...

  2. spring源码学习之bean的加载(一)

    对XML文件的解析基本上已经大致的走了一遍,虽然没有能吸收多少,但是脑子中总是有些印象的,接下来看下spring中的bean的加载,这个比xml解析复杂的多.这个加载,在我们使用的时候基本上是:Bea ...

  3. spring源码学习之bean的加载(三)

    接着二中的继续写,那个都超过1000行了,哈,需要重新写一个,要不太长了,我都看不下去了 7.4 初始化bean doCreateBean函数中有这样一行代码:这行代码中initializeBean函 ...

  4. Spring源码分析之Bean的加载流程

    spring版本为4.3.6.RELEASE 不管是xml方式配置bean还是基于注解的形式,最终都会调用AbstractApplicationContext的refresh方法: @Override ...

  5. 【Spring源码分析】非懒加载的单例Bean初始化过程(下篇)

    doCreateBean方法 上文[Spring源码分析]非懒加载的单例Bean初始化过程(上篇),分析了单例的Bean初始化流程,并跟踪代码进入了主流程,看到了Bean是如何被实例化出来的.先贴一下 ...

  6. 【Spring源码分析】非懒加载的单例Bean初始化前后的一些操作

    前言 之前两篇文章[Spring源码分析]非懒加载的单例Bean初始化过程(上篇)和[Spring源码分析]非懒加载的单例Bean初始化过程(下篇)比较详细地分析了非懒加载的单例Bean的初始化过程, ...

  7. Spring源码分析:非懒加载的单例Bean初始化前后的一些操作

    之前两篇文章Spring源码分析:非懒加载的单例Bean初始化过程(上)和Spring源码分析:非懒加载的单例Bean初始化过程(下)比较详细地分析了非懒加载的单例Bean的初始化过程,整个流程始于A ...

  8. Spring源码分析:非懒加载的单例Bean初始化过程(下)

    上文Spring源码分析:非懒加载的单例Bean初始化过程(上),分析了单例的Bean初始化流程,并跟踪代码进入了主流程,看到了Bean是如何被实例化出来的.先贴一下AbstractAutowireC ...

  9. 【Spring源码分析】非懒加载的单例Bean初始化过程(上篇)

    代码入口 上文[Spring源码分析]Bean加载流程概览,比较详细地分析了Spring上下文加载的代码入口,并且在AbstractApplicationContext的refresh方法中,点出了f ...

  10. Spring源码分析:非懒加载的单例Bean初始化过程(上)

    上文[Spring源码分析]Bean加载流程概览,比较详细地分析了Spring上下文加载的代码入口,并且在AbstractApplicationContext的refresh方法中,点出了finish ...

随机推荐

  1. https://scrapingclub.com/exercise/basic_captcha/

    def parse(self, response): # set_cookies = response.headers.getlist("set-cookie").decode(& ...

  2. 【Spark-core学习之二】 RDD和算子

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 scala-2.10.4(依赖jdk1.8) spark ...

  3. catch data

    抓取一些有反爬机制的website 喜马拉雅   每天都有-动态class 通过网络请求

  4. Why Choose MB SD C5 with Engineer Software

    MB SD C5 with engineer software performed good and now is released. Unlike the old clone C5 which us ...

  5. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  6. input 只能输入数字、字母、汉字等

    1.文本框只能输入数字代码(小数点也不能输入) <input onkeyup="this.value=this.value.replace(/\D/g,'')" onafte ...

  7. 【题解】Luogu P2057 [SHOI2007]善意的投票

    原题传送门 我们一眼就能看出这是一道最小割的题 我们设不睡觉这种状态为S,睡觉这种状态为T 对于每个人,如果不想睡觉,就从S向这个人连流量为1的边,否则,就从这个人向T连流量为1的边 对于每一对朋友, ...

  8. 在cef中使用自定义协议(scheme)

    在谷歌浏览器中点击设置,地址栏里出现的不是普通网址,而是chrome://settings/ 这个地址就是谷歌浏览器的自定义scheme,cef也提供了自定义协议手段.主要是通过 以下几步: 1.继承 ...

  9. HTTP的简单的解析

    HTTP 中文全称为超文本传输协议是一种为分布式,合作式,多媒体信息系统服务,面向应用层的协议.它是一种通用的,不分状态(stateless)的协议,除了诸如名称服务和分布对象管理系统之类的超文本用途 ...

  10. CSS常用伪类

    css伪类 :after 在元素后面插入内容 :hover 鼠标移入时进行 :before 在元素前面插入内容 :link 未选中的链接 :active 点击后产生什么变化 :nth-child 匹配 ...