spring 源码分析01
spring中获取bean的常见的方式,一般从BeanFactory中或者ApplicationContext中获取。因为ApplicationContext接口继承了BeanFactory接口,所以直接讲BeanFactory.getBean(String beanName)
AbstractBeanFactory的getBean调用的是该类的doGetBean方法
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {final String beanName = transformedBeanName(name);Object bean;// 从spring的三级缓存中获取bean---解决循环依赖的关键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.if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}//忽略部分代码.....try {final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);//忽略部分代码,getDependsOn依赖bean先加载.....// Create bean instance.if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {destroySingleton(beanName);throw ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else {String scopeName = mbd.getScope();final 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, () -> {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}});bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {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",ex);}}}catch (BeansException ex) {cleanupAfterBeanCreationFailure(beanName);throw ex;}}//忽略部分代码--类型的校验.....}return (T) bean;}
复制代码
上述的代码中大致的流程如下:
- 从Spring维护的三级缓存中获取一个singleton bean,获取成功直接返回
- 判断该bean是否处于创建中,如果是说明出现了循环依赖,抛异常
- 根据bean的作用域,分别用不同的方式获取bean,如果获取不到最终调用的都是同一个createBean方式
- getObjectForBeanInstance 如果上述方法获取到的是一个FactoryBean的情况下,需要从里面获取对应的我们需要的Bean
下面分析下singleton bean的获取
// Create bean instance.
if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {destroySingleton(beanName);throw ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
复制代码
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(beanName, "Bean name must not be null");synchronized (this.singletonObjects) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {if (this.singletonsCurrentlyInDestruction) {throw new BeanCreationNotAllowedException(beanName,"Singleton bean creation not allowed while singletons of this factory are in destruction " +"(Do not request a bean from a BeanFactory in a destroy method implementation!)");}if (logger.isDebugEnabled()) {logger.debug("Creating shared instance of singleton bean '" + beanName + "'");}beforeSingletonCreation(beanName);//定义异常...try {singletonObject = singletonFactory.getObject();newSingleton = true;}catch (IllegalStateException ex) {// Has the singleton object implicitly appeared in the meantime ->// if yes, proceed with it since the exception indicates that state.singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {throw ex;}}catch (BeanCreationException ex) {//封装异常...}finally {...afterSingletonCreation(beanName);}if (newSingleton) {addSingleton(beanName, singletonObject);}}return singletonObject;}}
复制代码
- 因为singleton的bean只能存在一个,所以对singletonObjects这个缓存做加锁获取
- 做循环依赖判断
- beforeSingletonCreation(beanName);//也就是把这个beanName标记成正在创建中
- 通过singletonFactory的方法获取bean --> 也就是调用createBean方法
- afterSingletonCreation(beanName);//去除该beanName正在创建中的标记
- 如果是新创建的singleton的bean的话,把他加入singletonObjects缓存中
- 这个singletonObjects缓存也就是上面所说的三级缓存的中的第一级(具体后续再说)
不管是singleton还是Prototype还是其他的scope,在从作用域中获取不到bean的情况下,都是调用的createBean
- 知识点梳理:
- FactoryBean:www.cnblogs.com/davidwang45…
- bean的作用域:
- singleton:整个容器中保留一份
- prototype:每次使用的时候,创建新的
- 其他scope
- SimpleThreadScope
- RequestScope
- SessionScope
转载于:https://juejin.im/post/5d272c57f265da1b6d405031
spring 源码分析01相关推荐
- 【转】Spring AMQP 源码分析 01 - Impatient
转自首夜盲毒预言家的文章 Spring AMQP 源码分析 01 - Impatient ### 准备 ## 目标 了解 Spring AMQP 核心代码 ## 前置知识 RabbitMQ 入门 ## ...
- Spring源码分析【1】-Tomcat的初始化
org.apache.catalina.startup.ContextConfig.configureStart() org.apache.catalina.startup.ContextConfig ...
- spring源码分析之spring-core总结篇
1.spring-core概览 spring-core是spring框架的基石,它为spring框架提供了基础的支持. spring-core从源码上看,分为6个package,分别是asm,cgli ...
- 【Spring源码分析】Bean加载流程概览
代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...
- 【spring源码分析】IOC容器初始化(二)
前言:在[spring源码分析]IOC容器初始化(一)文末中已经提出loadBeanDefinitions(DefaultListableBeanFactory)的重要性,本文将以此为切入点继续分析. ...
- spring源码分析第六天------spring经典面试问题
spring源码分析第六天------spring经典面试问题 1.Spring5 新特性及应用举例 2.Spring 经典的面试问题 a.什么是 Spring 框架?Spring 框架有哪些主要模块 ...
- spring源码分析第五天------springAOP核心原理及源码分析
spring源码分析第五天------springAOP核心原理及源码分析 1. 面向切面编程.可以通过预 编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术 切面(A ...
- spring源码分析第四天------springmvc核心原理及源码分析
spring源码分析第四天------springmvc核心原理及源码分析 1.基础知识普及 2. SpringMVC请求流程 3.SpringMVC代码流程 4.springMVC源码分析 4.1 ...
- spring源码分析第一天------源码分析知识储备
spring源码分析第一天------源码分析知识储备 Spring源码分析怎么学? 1.环境准备: 2.思路 看:是什么? 能干啥 想:为什么? 实践:怎么做? ...
最新文章
- 怎么控制table的大小java_如何查询Table占用空间的大小
- 安卓的自定义的DemoApplication 出现的问题。
- Android开发艺术探索》读书笔记 (8) 第8章 理解Window和WindowManager
- 【翻译】HTML5基于浏览器的媒体播放器:可以离线播放你的mp3文件
- 伟大:看谷歌如何造福人类健康事业
- ansible 部署ssh 偶尔巨慢的解决方法
- mybatis generator Unknown system variable 'query_cache_size' 的解决方法
- grep 命令的 12 个实例
- 响应式和自适应的区别
- 【转】系统缓存全解析一
- 【递归】n个数的全排列
- 使用火狐浏览器的原因是什么?使用英文版火狐的原因又是什么?
- 算子,滤波器,卷积模板,卷积核的概念比较
- POJ 3576 Language Recognition
- vs html复选框,组合框和复选框
- Jedis hget连接好久没有反应
- 汉字编码及显示原理总结
- 老大,不好了,内存泄漏了!
- 教你用OpenCV 和 Python给证件照换底色(蓝底 -红底-白底)
- Nginx 部署、反向代理配置、负载均衡
热门文章
- Stark 组件:快速开发神器 —— 模板设计
- Django学习~1
- 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言—— 1056:点和正方形的关系
- 大数据WEB阶段Spring框架(一)IOC控制反转、DI注入依赖
- 大数据WEB阶段(九)Servlet+Request
- 【Qt】Qt Creator中布局器详解
- 【ARM】协处理器指令
- LVS(8)——tcpdump查看数据包到底如何传递
- DevStack安装问题,git clone noVNC.git失败
- oracle使用sqlplus工具命令连接,快速启动oracle服务。