spring ioc的总结和疑点释义

介绍IOC整个加载流程

doGetBean 创建bean的整个逻辑主流程

1.首先获取真正的beanName:去掉&,查询别名

2.从缓存查询bean实例:先从singletonObjects获取,如果获取不到且该bean正在创建中,尝试从earlySingletonObjects获取如果还获取不到,如果允许创建早期的对象引用,则从singletonFactories获取objectFactory(即实例化好bean就放入singletonFactories,这解决循环依赖的关键),并创建bean对象(调用createBean),将结果存入earlySingletonObjects(存入的只是早期对象,相关属性还未塞入),从singletonFactories删除objectFactory获取。【其中将beanName和对应的objectFactory,放入singletonFactories,就是为了解决循环依赖】

3.如果从缓存中找到了bean实例返回真正的对象:然后根据原始的beanName参看,是否是查询factoryBean本身,如果不是单身查出来的又是factorybean对象,这说明是查询factoryBean的getObject,否则的话就是直接返回该实例(所有的bean创建完成准备返回前都需要经过这一步)

4.如果缓存中没有,准备去创建bean。

5.首先针对原型bean是否存在循环依赖进行检测:通过threalocal存储多例bean的beanName,当第一次存的时候是存的string,第二次就换成set,如果threadlocal中有这个beanName 则存在循环依赖,直接抛出异常。之所以原型bean的循环依赖无法解决就是因为原型bean spring是不缓存的 所以会无限创建导致oom

6.如果存在父beanFactory,则调用父beanFactory去创建bean

  1. 如果不是只为检测类型所用则表示bean已经创建:即在alreadyCreated集合中增加beanName,同时清除mergedBeanDefinitions该beanName的缓存是为了让我们实际创建的bean定义重新合并bean ...以防万一其中的某些元数据在此期间发生了变化。

8.如果我们beanName属于child beanDefinition,则此时继续从父类中获取相关属性,用于填充子类的beanDefinition:因为第七步清除缓存,所以第八步得以从新从父beanDefinition中获取相关属性,通过合并返回给定顶级bean的RootBeanDefinition

9.检测beanDefinition是否是是抽象的如果是就抛出异常

10.获取该bean所依赖的bean,然后先初始化依赖的bean:即获取xml或者注解涉及到的dependon 这个属性的所配置的bean然后初始化所以来的bean。首先获取所依赖的beanNames,然后判断beanNames是否包含beanName,如果是就抛出异常,不是的话,就将beanName和所依赖的dependNames互为key和value存放两个集合(dependentBeanMap,dependenciesForBeanMap)中。判断是否循环依赖的逻辑是:判断beanName的dependentBeanMap是否包含dependNames,如果是就说明是循环依赖,不是的话再从当前beanName依赖的dependentBeanMap获取已经依赖的beanName 与dependNames进行一一比较,如果这些中有一个有,那么就是循环依赖,抛出异常

11.根据bean的scope,分为单例,原型和Scope进行创建bean。

12.单例创建bean的逻辑:尝试从缓存singletonObjects获取,获取不到且bean处于正在销毁中则抛出异常。否则开始设置创建bean的标识(如果需要创建检测且singletonsCurrentlyInCreation不包含该beanName,则为正常否则抛出异常),调用objectFactory的getObject方法创建bean实例(其实底层是调用createBean ),创建成功取消bean正在创建的标识,如果是新创建的bean,则将bean放入缓存singletonObjects,把objectFactory从singletonFactories移除,从earlySingletonObjects移除bean引用(因为缓存中已经有了,这边在存一份浪费空间),registeredSingletons添加该bean

13.原型创建bean的逻辑:往threadlocal中塞入创建的bean的对应的beanName,然后调用createBean ,最终删除该beanName

14.Scope类型创建bean的逻辑:获取scopeName,根据scopeName获取scope,然后根据scope去创建bean,逻辑与原型创建一致。一般是sessionscope,requestscope,AbstractRequestAttributesScope,或者servletcontextscope从这可以看出各个bean的生命周期

15.如果requiredType存在且我们的bean不是requiredType类型的,我们需要强制进行转换。

createBean 创建bean的方法

1.获取需要解析的class:从mergedBeanDefinition里获取beanclass

2.如果beanClass确实存在,则深度拷贝mergedBeanDefinition:在动态解析的Class的情况下因无法存储在共享合并bean定义中 所以克隆bean定义

3.处理lookup-method和replace-method

4.调用实例化前的后置处理器,如果得到bean接着调用初始化后的后置处理器:这边有机会根据用户自定义的targetsource生成proxy然后直接返回

5.下面就是执行doCreateBean :开始真正的创建bean,然后填充属性,初始化bean。其中对应动态代理就是在初始化后的后置处理器开始生成

doCreateBean 实际创建bean的实例方法

1.如果是单例,首先尝试从factoryBeanInstanceCache获取instanceWrapper

2.如果instanceWrapper还是null,则尝试创建instanceWrapper:首先获取beanclass,并对class是否是public如果不是且没有权限访问则抛出异常,分别依次尝试Supplier,和factorymethod,无参的构造函数(在有缓存已经解析的构造函数或者工厂方法时候)去实例化,如果上面都不符合条件,说明是首次尝试实例化该类,那么再去选择一种合理的构造函数去实例化,如果这个也不行。那么就采用默认的构造函数去实例化

3.bean实例化好后,调用MergedBeanDefinitionPostProcessor去支持下面一些列的注解,即获取这些注解的信息存于缓存,等到后期设置属性和初始化时候进行调用:就是对于从beanDefinition获取AutowiringMetadata(@Autowired} @Value}),ResourceMetadata(@PostConstruct,@PreDestroy,@Resource等其他JSR-250注解),LifecycleMetadata(@InitializingBean和@DisposableBean)

4.如果是支持单例的循环依赖,且当前是当了则将未初始化的bean暴露出来

5.填充bean的属性

6.初始化bean

7.检测bean的循环依赖:如果bean是支持循环依赖的,尝试从缓存获取,如果获取到的bean,如果获取到了继续比较初始化前后bean是否相同,如果相同,则将缓存中的返回,否则检测下该bean依赖的bean是否已经实例化好了,如果没有则有可能是出现循环依赖,抛出异常。(这边的循环依赖指的是该bean dependon的bean是否已经实例化好了)

8.最后注册一个disposableBean和给定的destroy方法


如何解决循环依赖:不论是原型还是单例对于构造函数注入的循环依赖都无法解决,因为构造函数注入会导致bean永远无法实例化,而原型的set注入或者其他注入也无法解决,因为spring不缓存非单例bean。只有单例的bean,spring通过实例化该bean然后缓存他,再去初始化他,如果这个时候其内部有个依赖对象,我们再去实例化这个对象,然后也放入缓存 再去初始化他,这样两者就不会无线创建bean

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容