Spring的初始化过程
容器先初始化 就是调用复合方法refresh bean的生命周期是在refresh方法里面的 这个refresh方法里面和bean生命周期关系最大的两个方法是 registerBeanPostProcessors(beanFactory);
finishBeanFactoryInitialization(beanFactory) :这个方法将会对非延迟加载的单例Bean进行预实例化
他们都调用的getBean->doGetBean
bean的生命周期:spring先将打了@service这种注解的bean解析成BeanDefinition,并以beanName为key BeanDefinition为value存在concurrentHashMap里面 并且把bean再存在一个list里面 遍历这个list进行bean的实例化
bean的实例化就是先调用构造方法 然后通过beanwrapper进行依赖注入 然后看看有没有aware接口init-method什么的 也就是bean的生命周期的前面的几个过程
实例化完了就放在一级缓存里面
这个依赖注入是在getBean方法里面完成的。这个getBean实际上是AbstractBeanFactory的getBean
getBean(1.创建一个新的bean 2.从缓存里面拿bean)—>doGetBean–>getSingleton【这个方法就是尝试去三级缓存里面拿bean】–>getSingleton(a,()->{})【这是一个重载方法 作用就是创建bean创建完了就放进三级缓存 包括实例化/属性注入/初始化】-
上面这张图是创建bean的 也就是getSingleton的重载方法
如果不是延迟加载 ioc容器初始化的时候也会调用这个getBean 进行提前依赖注入 预实例化
如果延迟加载 那么就先初始化ioc 然后到了getBean这一步的时候 再来初始化bean
Bean的生命周期
1.实例化Bean:
IOC容器通过获取BeanDefination对象的信息进行实例化,实例化对象被包装在BeanWrapper(Bean的包装)对象中
2.设置对象的属性(DI依赖注入):getbean方法 --> createBean–>createBean里面的populateBean
真正执行依赖注入的就是populateBean()方法 就一行代码
但是这个方法最终调用的是beanwrapper接口的setPropertyValues方法 完成属性的注入
3.注入Aware接口():Spring会检测该对象是否实现了xxxAware()接口,并将相关的xxxAware实例注册给bean
【Aware接口就是增强bean的感知 接口里面啥也没有 但是BeanNameAware接口 继承Aware接口 然后有个setBeanName方法
如果bean实现了BeanNameAware接口,spring将bean的id传给setBeanName()方法;
如果bean实现了BeanFactoryAware接口,spring将调用setBeanFactory方法,将BeanFactory实例传进来】
4.BeanPostProcessor:自定义的处理(分为前置处理和后置处理)
5.InitializingBean 和 init-method:执行我们自己定义的初始化方法,也就是说是afterPropertiesSet()方法里面的内容 init-method是属性
6.使用
7.destory:bean的销毁 当然对应的肯定有DisposableBean接口和destroy-method属性
循环依赖
是什么?
就像controller依赖service service依赖dao一样
A依赖B B依赖C C依赖A
能解决的前置条件:
1.出现循环依赖的bean必须是单例
2.依赖注入的方式不能全是构造器注入
全是setter注入肯定没问题了能解决
setter+构造器注入也行好像还能搏一搏
如果是构造器注入呢 怎么办?
@lazy注解 让spring懒加载 当真正用到的时候 再去加载
对象实例化分为三步:
1.createBeanInstance():调用对象的构造方法实例化
2.populateBean() :属性填充
3.initializeBean() :调用spring xml中的init方法初始化
三级:singletonFactories : 早期曝光对象工厂
二级:earlySingletonObjects :早期曝光对象
一级:singletonObjects:单例池
怎么解决的?
通过三级缓存 我们创建对象分为三步 先调用构造函数实例化 然后属性填充 再初始化 允许调用构造函数之后 即使属性未填充 可以通过三级缓存提前暴露 就是把bean包装成一个工厂放进三级缓存 如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象。
创建bean的时候Spring先从一级缓存中获取 获取不到就去二级缓存里面找 如果还找不到就去三级缓存通过singletionFactory.getObject()方法获取 如果获取到了就放进二级缓存里面
为什么要使用三级缓存呢?二级不可以吗?
如果用二级缓存 意味着Bean在实例化之后就完成AOP代理 但是Spring的设计原则是在Bean生命周期的最后一步完成AOP代理
所以spring解决循环依赖的关键就在于这个三级缓存 而加入三级缓存的前提是执行了构造器 所以纯构造器的循环依赖没办法解决
(可以通过@lazy注解延迟加载)
将bean包装成一个工厂 添加进了三级缓存
举例子:
比如A依赖了B B依赖了A A先进行初始化 刚完成第一步执行完构造方法 发现自己依赖B 就尝试去get(B) 但是这个时候B还没有呗创建出来 (这个时候已经暴露了)于是创建B B在初始化第一步的时候发现自己依赖A 然后去一级缓存里面找A 找不到 二级缓存 找不到 三级缓存 由于A将自己提前暴露了 所以B能拿到A 然后B就完成了初始化 把自己放进了一级缓存里面 然后A也完成了初始化