博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring源码阅读笔记--主要实现步骤
阅读量:3948 次
发布时间:2019-05-24

本文共 4223 字,大约阅读时间需要 14 分钟。

一、核心流程

1、从资源读取bean的创建信息(BeanDefinition)

读取spring的xml配置文件,得到bean的创建信息BeanDefinition,最终bean的信息保存在DefaultListableBeanFactory.beanDefinitionMap,该类提供对象仓储88服务

private final Map<String, BeanDefinition> beanDefinitionMap
= new ConcurrentHashMap<>(256);

2、解析bean信息得到bean对象,扫描bean信息,循环依赖,注入属性,保存到内存集合

单例模式对象,从缓存读取singletonObjects,singletonFactories,earlySingletonObjects

非单例模式,每次创建新对象,工厂方法或者构造函数创建。

3、用户得到bean对象

通过context或factory对象得到

.

1、读取bean信息 详细步骤:

1.1、jvm运行jar包,加载jar里的类信息到方法区,

1.2、用类路径资源加载对象(ClassPathResource),获得当前类信息下的附属配置文件,
1.3、读取文件构建资源对象
1.4、用资源创建一个xmlbean工厂对象(XmlBeanFactory)

1.4.1、XmlBeanFactory 继承DefaultListableBeanFactory XmlBeanFactory 依赖XmlBeanDefinitionReader

1.4.2、DefaultListableBeanFactory 是spring注册加载bean的默认实现 和xmlbeanFactory主要区别是用到XmlBeanDefinitionReader
DefaultListableBeanFactory 继承自 AbstractAutowireCapableBeanFactory 实现了
ConfigurableListableBeanFactory BeanDefinitionRegistry 和 Serializable
接口

1.5、XmlBeanFactory解析资源,得到bean的创建信息,

.

2、解析bean信息得到bean对象 详细步骤:

2.1、转换对应的beanName,(从beanName,别名, FactoryBean)

2.2、尝试从缓存中加载单例,(bean缓存,singletonFactories ,循环依赖先暴露ObjectFactory)

如果从中得到了bean的原始状态,则进行bean实例化

(什么是原始状态object,有可能是bean对象,匜有可能是继承了FactoryBean的工厂对象,通过判断类型instanceof
FactoryBean做处理,如果是工厂创建的bean有独立的缓存)

2.3、如果加载不到缓存,先判断是否是原型循环依赖(isPrototypeCurrentlyInCreation)是的话抛异常(BeanCurrentlyInCreationException)

2.4、如果该beanName在当前beanFactory里找不到(beanDefinitionMap (XML配置文件)里没有该bean),且有父级beanFactory,就调用父级的getBean(检查AbstractBeanFactory,BeanFactory,构造参数,指定返回类型,分情况处理)
2.5、如果beanName在当前beanFactory里找得到,继续按主线流程获得bean
2.6、进行depends-on标签判断,如果有强依赖关系,比如分析文件的bean只能在载入文件的bean后面创建,则先创建depends-on标签指定的bean,
例子参考
2.7、前置条件走完了,开始创建bean了,根据作用域分为单例模式,原型模式,其他三种情况
2.8、单例模式创建bean,从缓存读取,缓存没有则调用createBean创建,最后调
2.9、原型模式创建bean
2.10、其他自定义情况创建bean(request、session、global session)
预先实现自定义的Scope保持在this.scopes缓存,
把本对象的getbean相关方法封装定义成一个ObjectFactory<?>
根据名称从.scopes缓存找到对应的Scope,调用Scope.get(beanName,ObjectFactory<?>)得到bean

.

单例模式创建bean时的补充说明

2.8.1、常用缓存对象

1)用于保存BeanName和创建bean实例之间的关系

private final Map<String, Object>singletonObjects = new ConcurrentHashMap<>(256);

2)用于保存BeanName和创建bean的工厂之间的关系

private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

3)也是保存BeanName和创建bean实例之间的关系,与singletonObjects不同之处在于,当一个单例bean被放在里面后那么bean还在创建过程中,就可以通过getBean方法获取到了,其目的是用来循环检测引用

private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

4)用来保存当前所有已注册的bean名称

private final Set registeredSingletons = new LinkedHashSet<>(256);

.

2.8.2 getSingleton方法

1、检查缓存是否已经加载过;

2、如果加载过直接返回缓存中的 bean;如果没有加载,则记录 beanName 的正在加载状态,用于循环依赖检查 ;
3、加载单例前记录加载状态;
4、当 bean 加载结束后需要移除缓存中对该 bean 的正在加载状态的记录。
5、将结果记录至缓存并删除加载 bean 过程中所记录的各种辅助状态;

循环依赖

构造器循环依赖,setter循环依赖,构造器和setter混合循环依赖,第一个是构造器则异常 Spring首先从一级缓存
singletonObjects 中获取,如果获取不到,并且对象正在创建中,就再从二级缓存 earlySingletonObjects
中获取。如果还是获取不到且允许 singletonFactories 通过 getObject() 获取,就从三级缓存
singletonFactory.getObject() 中获取。一旦从三级缓存中获取到了,将 singletonFactories
中移除掉缓存,并将创建出的 bean 放入 earlySingletonObjects 中,其实也就是从三级缓存移动到了二级缓存。 可以通过
XmlBeanFactory.setAllowCircularReferences(false)
来禁用循环依赖,这样就Spring不会尝试解决这一问题,直接抛出异常

.

2.8.3 getObjectForBeanInstanc方法

从工厂bean的实例中获取对象,这个方法是各种getbean的最后一步处理,之前保存的bean对象有可能是工厂类的实例,这里判断如果是工厂类的实例则通过工厂类的getObject()得到真实的bean,

(1)getObjectForBeanInstance判断合法,缓存,核心是调getObjectFromFactoryBean,
(2)getObjectFromFactoryBean判断单例和非单例,核心调doGetObjectFromFactoryBean
(3)doGetObjectFromFactoryBean里判断权限,核心调FactoryBean 的 getObject()

.

2.8.4 createBean方法

1、类型验证转换,设置 class 属性或者根据 className 来解析 class ;

2、对 MethodOverride 属性进行验证及标记;
3、aop入口,应用初始化前的处理器,解析指定 bean 是否存在应用初始化前的aop短路操作
resolveBeforeInstantiation;如果前处理已经得到了bean就调用后处理器,跳过doCreateBean
4、创建 bean。(doCreateBean)
.

2.8.5 doCreateBean方法

1 、如果是单例模式,首先从缓存中尝试 remove 得到 BeanWrapper;

2、如果缓存中没有,则根据 BeanDefinition 转换为 BeanWrapper;
3、通过前两步,我们得到 BeanWrapper 后,进行 MergedBeanDefinitionPostProcessors 的应用。主要是 bean 合并后的处理,@AutoWire 就是基于这个方法实现诸如类型的预解析;
4、处理 bean 的依赖;
5、对bean进行填充,将各个属性值注入 bean;
6、循环依赖检查,检测已经加载的 bean 是否已经出现了依赖循环,并判断是否要抛出异常;
7、注册 DisposableBean。如果XML配置了 destory-method,这里需要注册以便于销毁 bean 的时候调用;
8、完成创建并返回。
9、原型模式创建bean
10、其他自定义情况(request、session、global session)
预先实现自定义的Scope保持在this.scopes缓存,
把本对象的getbean相关方法封装定义成一个ObjectFactory<?>
根据名称从.scopes缓存找到对应的Scope,调用Scope.get(beanName,ObjectFactory<?>)得到bean

参考文章

Spring源码——bean的加载

转载地址:http://ithwi.baihongyu.com/

你可能感兴趣的文章
转 hook 自绘原理
查看>>
NSIS 脚本介绍
查看>>
记录通讯日志的函数
查看>>
c++ 标准容器介绍与对比
查看>>
web DB优化思路
查看>>
敏捷笔记
查看>>
SOA业务理解与应用
查看>>
Google File System(中文翻译)
查看>>
Google's BigTable 原理 (翻译)
查看>>
MapReduce:超大机群上的简单数据处理
查看>>
设计模式笔记(转载)
查看>>
加站点加入IE的可信站点做法
查看>>
软件研发中的《破窗理论》
查看>>
敏捷的三种误区和五种改进
查看>>
用数字来看某知名B2C网站的发展内幕和隐私
查看>>
vs2010一些设置
查看>>
生活感悟语录
查看>>
用python中htmlParser实现的spider(python spider)
查看>>
在线测速网址
查看>>
mysql中GROUP_CONCAT的应用
查看>>