Spring源码阅读笔记--主要实现步骤

一、核心流程

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,
例子参考https://www.cnblogs.com/sxdcgaq8080/p/5681350.html
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的加载
https://blog.youkuaiyun.com/bskfnvjtlyzmv867/article/details/82859993

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值