本篇文章,来介绍finishBeanFactoryInitialization(beanFactory);这个方法主要是完成bean的实例化,

invokeBeanFactoryPostProcessors(beanFactory);负责把所有的bean扫描到beanDefinitionMap中;

下面来说是如何初始化的

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

我们直接从这个方法开始说起,前面的调用链简单,就不说了

 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { /**
* 通过name获取beanName,这里不使用name直接作为beanName有两个原因:
* 1.name可能是以&开头的,表明调用者想获取FactoryBean本身,而非FactoryBean;在beanFactory中factoryBean的存储也是map格式
* <beanName,bean> 只是说,普通的beanName是没有&这个字符串的,所以,需要将name的首字母移除,这样才能从缓存中拿到factoryBean
* 2.还是别名的问题,需要转换
*/
final String beanName = transformedBeanName(name);
Object bean; /**
* 1.从单例池中获取当前bean
* 2.这里是循环依赖的重要方法之一
*
*/
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
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 + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
/**
* 这里判断bean是否在创建过程中,是第二次调用的时候 才会判断;如果是第一次执行到这里,set集合是空(这里判断的是原型bean)
*/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
} //添加到alreadyCreated集合当中,表示当前bean已经创建过一次了
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
} try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on.
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 {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
} // Create bean instance.如果当前bean是单实例的,就调用createBean
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;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
} return (T) bean;
}

粘贴出来的方法删减了一部分代码,我们只说单实例bean的初始化;

在判断当前bean是单实例的时候,会调用createBean;在getSingleton这里,有一行代码,是把当前bean添加到一个set集合中(这个set集合表示当前bean正在创建过程中),

这个set是用来解决循环依赖问题的,在后面,会单独抽出一篇来介绍循环引用是如何解决的,在这里就先跳过;

在createBean的方法中,会调用createBeanInstance(beanName, mbd, args); 这个方法主要是完成bean的初始化,在方法中会调用org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors;

这个后置处理器的determineCandidateConstructors方法来推断使用哪个构造函数来初始化;

这个方法里面,我目前也正在学习,后续会贴出对这个方法的学习笔记,这里先暂时跳过;(我们就认为createBeanInstance方法完成了bean的创建),

推断出使用哪个构造函数之后,会初始化bean,返回的是一个BeanWrapper对象。这里创建出来的仅仅是bean对象;需要经过后面的属性注入,以及初始化,才会变成我们所说的spring bean对象;

 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException { // Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
/**
* 创建bean实例,并将bean实例包裹在BeanWrapper实现类对象中返回,
* createBeanInstance中包含三种创建bean的方式
* 1.通过工厂方法创建bean实例
* 2.通过构造方法自动注入的方式创建bean实例
* 3.通过无参构造方法创建bean实例
*
* 如果bean的配置中配置了lookup-method和replace-method 则会使用增强bean实例
*
* 在这个方法中完成了对bean的创建(仅仅是new出来,也就是说在这个方法里面推断要使用哪个构造函数来创建bean对象)
* 然后完成bean的初始化
*
*/
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
} // Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
//mpy 第三次调用后置处理器 缓存注解信息
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
} // Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//mpy 第四次调用后置处理器 获取一个提前暴露的对象 用来解决循环依赖
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
} // Initialize the bean instance.
Object exposedObject = bean;
try {
//在populateBean(beanName, mbd, instanceWrapper);方法中完成第五次第六次调用后置处理器
populateBean(beanName, mbd, instanceWrapper);
//在initialzeBean中完成第七次第八次后置处理器调用
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
return exposedObject;
}

上面这个方法中,调用第四次后置处理器这里,返回了一个object对象,这个方法是为了完成循环依赖的,放到后面一起讲,

在populateBean中,会完成属性的注入,比如@AutoWired,@Value这个属性值注入

initializeBean方法,主要是调用bean的初始化方法

bean的初始化有三种方式:

1.@Bean注解中指定 initMethod destroyMethod

2.@PostConstruct @PreDestroy

3.实现DisposableBean和InitializingBean接口

在方法执行完之后,会把创建好的bean对象存放到singletonObjects这个map中,这个map存放的是所有实例化好的对象;如果bean是原型的,在第二次getBean的时候,会从这个map中获取到bean对象

从狭义上来讲,singletonObjects就是我们所说的spring容器

spring源码学习(二)的更多相关文章

  1. [spring源码学习]二、IOC源码——配置文件读取

    一.环境准备 对于学习源码来讲,拿到一大堆的代码,脑袋里肯定是嗡嗡的,所以从代码实例进行跟踪调试未尝不是一种好的办法,此处,我们准备了一个小例子: package com.zjl; public cl ...

  2. spring源码学习之路---IOC初探(二)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章当中我没有提及具体的搭 ...

  3. Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作

    写在前面 上文 Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件主要讲Spring容器创建时通过XmlBeanDefinitionReader读 ...

  4. Spring源码学习

    Spring源码学习--ClassPathXmlApplicationContext(一) spring源码学习--FileSystemXmlApplicationContext(二) spring源 ...

  5. Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签

    写在前面 上文Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作中Spring对XML解析后创建了对应的Docum ...

  6. Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件

    写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...

  7. Spring源码学习笔记9——构造器注入及其循环依赖

    Spring源码学习笔记9--构造器注入及其循环依赖 一丶前言 前面我们分析了spring基于字段的和基于set方法注入的原理,但是没有分析第二常用的注入方式(构造器注入)(第一常用字段注入),并且在 ...

  8. Spring 源码学习笔记10——Spring AOP

    Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...

  9. Spring 源码学习笔记11——Spring事务

    Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ...

  10. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

随机推荐

  1. 【转+】python为什么推荐使用多进程

    最近在看Python的多线程,经常我们会听到老手说:“Python下多线程是鸡肋,推荐使用多进程!”,但是为什么这么说呢?                要知其然,更要知其所以然.所以有了下面的深入研 ...

  2. mysql执行过程以及顺序

    前言:mysql在我们的开发中基本每天都要面对的,作为开发中的数据中间件,mysql承担者存储数据和读写数据的职责.因为学习和了解mysql是至关重要的,那么当我们在客户端发起一个sql到出现详细的查 ...

  3. WordPress 使用本地化的 emoji 表情包

    WordPress 结合使用 Native Emoji 和 WP Local Emoji 两个插件,可以达到使用本地化的 emoji 表情包的目的. 安装好上述两个插件并且启用: 为了使 Native ...

  4. 新手安装vue-cli脚手架

    首先这片文章借鉴了很多博主的,再此对他们表示感谢. 什么是vue? Vue.js是一套构建用户界面的渐进式框架.Vue 只关注视图层,采用自底向上增量开发的设计. Vue 的目标是通过尽可能简单的 A ...

  5. Springboot之初入江湖

    Hello,各位小伙伴大家好,我是小栈君. 今天的分享主题是关于Springboot主题分享,其实在写这个系列主题之前有想过一些关于分享技术的顺序问题,因为我在创建"IT干货栈"这 ...

  6. orm加强版

    目录 十三式 2式(针对外键查询优化) select_related和prefetch_related prefetch_related 查询返回值类型 不等式查询 关键字查询 时间查询 跨表查询 组 ...

  7. QR 码详解(下)

    快速响应矩阵码(下) 书接上回,继续下半场. 纠错码 QR 码采用纠错算法生成一系列纠错码字,添加在数据码字序列之后,使得符号可以在遇到损坏时可以恢复.这就是为什么二维码即使有残缺也可以扫出来.没有残 ...

  8. TP框架配合jquery进行3种方式的多图片上传

    用的TP5.1框架+jquery 一 使用form表单方式进行多图片上传 html代码: <form action="../admin/admin/cs" enctype=& ...

  9. HDU 1428漫步校园

    漫步校园 Problem Description LL最近沉迷于AC不能自拔,每天寝室.机房两点一线.由于长时间坐在电脑边,缺乏运动.他决定充分利用每次从寝室到机房的时间,在校园里散散步.整个HDU校 ...

  10. SVN应用

    一:从服务器上down资料 1.在电脑上安装SVN客户端 2.在电脑本地创建个文件夹作为版本库 3.进入xfssvn文件夹右击鼠标选择SVN Checkout或SVN Update 4.输入服务器中配 ...