spring源码学习(二)
本篇文章,来介绍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源码学习(二)的更多相关文章
- [spring源码学习]二、IOC源码——配置文件读取
一.环境准备 对于学习源码来讲,拿到一大堆的代码,脑袋里肯定是嗡嗡的,所以从代码实例进行跟踪调试未尝不是一种好的办法,此处,我们准备了一个小例子: package com.zjl; public cl ...
- spring源码学习之路---IOC初探(二)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章当中我没有提及具体的搭 ...
- Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作
写在前面 上文 Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件主要讲Spring容器创建时通过XmlBeanDefinitionReader读 ...
- Spring源码学习
Spring源码学习--ClassPathXmlApplicationContext(一) spring源码学习--FileSystemXmlApplicationContext(二) spring源 ...
- Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签
写在前面 上文Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作中Spring对XML解析后创建了对应的Docum ...
- Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件
写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...
- Spring源码学习笔记9——构造器注入及其循环依赖
Spring源码学习笔记9--构造器注入及其循环依赖 一丶前言 前面我们分析了spring基于字段的和基于set方法注入的原理,但是没有分析第二常用的注入方式(构造器注入)(第一常用字段注入),并且在 ...
- Spring 源码学习笔记10——Spring AOP
Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...
- Spring 源码学习笔记11——Spring事务
Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ...
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
随机推荐
- freemarker常用属性
1.th:action 定义后台控制器的路径,类似<form>标签的action属性. 示例如下. <form id="login" th:action=&quo ...
- maven scope属性说明
一.scope属性: 依赖范围控制哪些依赖在哪些classpath 中可用,哪些依赖包含在一个应用中. compile (编译) compile是默认的范围:如果没有提供一个范围,那该依赖的范围就是编 ...
- java基础之循环遍历List和Map
List和Map是在编程中使用的最频繁的集合类型了,每天都不知道要见它们多少面.在这里介绍下这两种类型的循环遍历,以供学习参考和使用. 一.List 遍历List一般有三种方法,如下: List< ...
- LeetCode 题解汇总
前言 现如今,对于技术人员(软开.算法等)求职过程中笔试都是必不可少的(免笔试的除外,大部分人都需要笔试),而笔试一般组成都是选择.填空.简答题.编程题(这部分很重要),所以刷题是必不可少的:对于应届 ...
- Android自动跳过app开屏广告
跳过开屏广告,体验流畅人生 开屏广告 是应用启动时显示的广告,一般右下角(或右下角)有倒计时跳过,不主动点击就会 等待3到5秒 后再进入App 自动跳过 是跳过应用的开屏广告的App 一图胜千文,来我 ...
- request.getPathInfo()的作用
项目中使用该方法来获取URL,但不知道获取的URL的起始: 如:http://localhost:8080/web_hrs/Action/这里可以是任何东西 ---->request.getP ...
- scalikejdbc 学习笔记(3)
重用connection: package com.citi.scalikejdbc import scalikejdbc._ import scalikejdbc.config._ object C ...
- ActiveMQ学习总结------实战操作(上)02
相信大家通过上一篇博文已经对ActiveMQ有了一个大致的概念了, 那么本篇博文将带领大家一步一步去实战操作我们的ActiveMQ 本篇主要内容: 1.ActiveMQ术语及API介绍 2.Activ ...
- A-07 前向分步算法
目录 前向分步算法 一.前向分步算法引入 二.前向分步算法详解 2.1 加法模型 2.2 加法模型目标函数优化问题 三.前向分步算法流程 3.1 输入 3.2 输出 3.3 流程 更新.更全的< ...
- 模拟telnet协议C语言客户端程序
首先要了解telnet协议,一下两篇blog给了我初步的思路 https://www.cnblogs.com/liang-ling/p/5833489.html 这篇有比较基础的介绍 以及IAC命令含 ...