关于Spring IOC加载全流程

@关于Spring IOC加载全流程

在网上读了很多关于Spring IOC AOP但是总会断断续续看不明白,实在无奈自己写了一份

先贴上一个流程图,对着流程图往下看
在这里插入图片描述

这里主要讲解是AnnotationConfigApplicationContext,主要三个方法,
this();//调用构造函数
register(annotatedClasses); // 注册配置类
refresh();//IOC容器刷新接口
以下对这些方法逐一介绍

this();

init BeanDefinitionRegister: 把ApplicationContext对象赋值给AnnotatedBeanDefinitionReader
关于项目中所有Bean注册,删除,判断是否为接口,获取等对BeanDefintion常用接口基本都在这里
ConditionEvaluator: 初始化一些环境变量类加载器等
注册内置后置处理器: 注册了,
ConfigurationClassPostProcessor: 解析配置类后置处理器
,AutowiredAnnotationBeanPostProcessor:解析@AutoWired后置处理器
RequiredAnnotationBeanPostProcessor:解析@Required后置处理器
CommonAnnotationBeanPostProcessor:处理JSR后置处理器
PersistenceAnnotationBeanPostProcessor:JPA后置处理器
EventListenerMethodProcessor:处理监听方法@EventListener解析器
DefaultEventListenerFactory:注册事件监听器工厂
创建BeanDefintion的扫描器BeanDefintionScanner

register(annotatedClasses);

DoRegisterBean
保存ConfigurationClass配置类
设置作用域,解析一些通用注解: Lazy,Primary,DependsOn,Role,Description
调用RegisterBeanDefinition: 图片上详解

refresh();

prepareRefresh();

  1. initPropertySources(); spring扩展接口可由开发者自己实现
  2. 校验容器启动必须的环境变量
  3. 创建一个早期的事件监听器
  4. 创建一个容器保存早期创建的事件,早期事件:是还没有放到多播器中的事件。不需要我们手动publishEvent发布,在Registerlisteners中会自动发布,发布完之后事件就会删除
    obtainFreshBeanFactory(); 告诉子类初始化Bean工厂,不同工厂有不同的实现
    prepareBeanFactory(BeanFactory): 对Bean工厂设置属性,后置处理器监听器等。。。。
    postProcessBeanFactory(beanFactory): 这个也是留给开发者自己实现的后置处理器方法
    实现BeanFactoryPostProcessor接口重写postProcessBeanFactory()
    invokeBeanFactoryPostProcessors: 调用我们Bean工厂的后置处理器,这个方法极为重要。
    后面会对这个方法重点说明
    registerBeanPostProcessors: 在这里会给项目中后置处理器进行排序添加到BeanPostProcess缓存中
    initMessageSource(): 初始化国际化资源处理器
    initApplicationEventMulticaster(): 创建事件多播器
    onRefresh(): 留给开发者实现, springboot启动就是通过重写这个方法
    registerListeners(): 把事件注册到事件多播器上
    finishBeanFactoryInitialization(beanFactory): 实例化单例Bean
    finishRefresh(): 刷新容器
    以上是spring容器启动的所有方法。spring容器大体流程。了解完大体流程之后,一起来了解一下里面细节,带着问题:spring容器是如何扫描包,怎么注册Bean定义,Import导入是如何解析,为什么Bean的作用域默认是单例,spring是如何解决依赖循环,AOP动态代理和事物的动态代理如何实现。

invokeBeanFactoryPostProcessors: 这个方法比较重要且是Spring里占有最为重要的一个方法,所以拿出来详解

在这里插入图片描述
前面会做一些后置处理器的排序,保存等基本操作。真正解析是在invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);调用ConfigurationClassPostProcess后置处理器的postProcessBeanDefinitionRegistry()
在这里插入图片描述
调用processConfigBeanDefinitions(registry);
在这里插入图片描述
上面都是获取项目中配置类什么的就不截图下来了。上面流程图很清楚可以看看大致的,讲一些关键点。代码331行,parser.parse(candidatest)方法
在这里插入图片描述
通过调用会来到这个processConfigurationClass方法,递归处理类以及超类层次结构
调用doProcessConfigurationClass(configClass,sourceClass,filter);
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 解析配置类里面的嵌套类
  2. 解析@PropertySource
  3. 从我们的配置类上解析处@ComponentScans的对象集合属性
  4. 处理 @Import annotations
  5. 处理 @ImportResource annotations
  6. 处理 @Bean methods 获取到我们配置类中所有标注了@Bean的方法
  7. 处理配置类接口 默认方法的@Bean
  8. 处理配置类的父类的 ,循环再解析
  9. 没有父类完成解析

解析@ComponentScans对象请看311行代码的parse方法
在这里插入图片描述
在这里插入图片描述

  1. 设置默认扫描规则为ture,默认是扫描所有的指定包下面Component,若使用 includeFilters 来表示只包含需要设置为false,在配置类中配置ComponentScan=(useDefaultFilters = false)。扫描你自己指定注解,这里还是默认配置没有特殊场景尽量不要修改
  2. 为扫描器设置BeanName生成器对象
  3. 解析@Scope的proxymode属性,这个属性可以将Bean创建为JDKProxy或者是CGLIBProxy
  4. 设置CompentScan对象的includeFilters 包含的属性
  5. 设置CompentScan对象的excludeFilters 包含的属性
  6. 是否懒加载,此懒加载为componentScan延迟加载所有类
  7. 调用doScan进行扫描解析。
    doScan: 扫描包下面的所有候选Components
    注意: 这扫描的时候如果你指定includeFilters并且设置为false,除这个包含的之外其他的不会扫描
    1.1 获取资源下面的所有resouce也就是.class文件。遍历所有resouce,
    1.2 判断是否可读,不可读的话会抛出一个异常,
    1.3 判断是否为候选组件,也就是includeFilters和excludeFilters
    1.4 封装成ScannedGenericBeanDefinition
    1.5 设置BeanName
    1.6 默认配置autowire-candidate
    1.7 获取@Lazy @DependsOn等注解的数据设置到BeanDefinition中
    1.8 把通过扫描解析出来的BeanDefintion注册到容器中,没有才会注册
  8. 扫描之后得到的BeanDefintion进行一个判断,看还有没有其他配置类,如果有就继续扫描。至此我们ComponentScan的扫描告一段落。
  9. 接下来是处理@Import
    1.1 如果实现了ImportSelector组件:如果没有实现延时组件DeferredImportSelector:这个是springboot框架就是用这个做的。没有实现找到对应的类,递归解析成一个普通的组件为止,普通组件会放到imports这个Map中。然后把这个class作为一个普通Bean进行解析
    1.2 如果导入组件实现了ImportBeanDefinitionRegistrar,会记录下来put到importBeanDefinitionRegistrars集合中
    1.3 如果是一个普通的Bean那就走解析Bean的逻辑,也就是1.1说的会递归解析到一个普通的Bean为止
  10. 处理@ImportResource
    1.1 这里找到直接解析出来保存到importedResources Map中
  11. 处理@Bean注解,保存到beanMethods set
  12. 处理父类接口信息。没有的话直接return,有父类会循环解析
    好了到这里基本上已经解析完了。现在回到processConfigBeanDefinitions(register)这个方法来。
    这里通过注解解析到的Bean放到configClasses中。接下来会调用
this.reader.loadBeanDefinitions(configClasses);

把它注册到BeanDefintionMap。注册顺序@Import,@bean,@ImportResources,@ImportBeanDefinition
至此已经把项目组需要的Bean都已经注册到BeanDefintionMap中。接下来是如何实例化,初始化,动态代理,这些。看到这里就更要花点耐心看下去了。因为下面更加的重要。

finishBeanFactoryInitialization(beanFactory)
有一些简单的看流程图,就不在这里一一解析,直接进入到主题吧。

//实例化剩余的单实例bean
beanFactory.preInstantiateSingletons();
  1. 先合并Bean定义,统一转化成RootBeanDefintion类型,方便解析

  2. 必须不是抽象类,是单例,不是懒加载才会getBean

  3. 判断是不是FactoryBean. 先说一下正常Bean没有实现FactoryBean的

  4. 不是FactoryBean。
    1.1 从缓存中获取getSingleton()下面有对这个方法的详解
    1.2 缓存中没有。
    1.3 判断是不是构造器注入。这种情况是spring不支持的会抛出异常
    1.4 类检查
    1.5 判断当前bean是不是抽象,抽象bean不能被实例化。很多同学会问那为什么Mapper可以。丢。mapper会实现FactoryBean
    1.6 检查@dependsOn注解.这逻辑很简单。只是看你依赖的这个是否已经注册,如果注册就报错,没有注册就先保存依赖,然后继续走下面的getBean给你当前这个Bean注册
    1.7 getSingleton(String beanName, ObjectFactory<?> singletonFactory) 方法重写
    检查一级缓存中是否存在,不存在继续走下面创建逻辑。标记当前Bean为正在创建的Bean。通过函数接口方法回调到**createBean()**方法。
    1.8 完成对象初始化,注册销毁Bean
    1.9 把当前对象从singletonsCurrentlyInCreation标记为正在创建集合移除
    2.0 加入一级缓存

  5. 完成一个Bean从扫描,解析,属性赋值,实例化,初始化结束

  6. 最后最后一个,循环所有在一级缓存中Bean,查看是否有重写afterSingletonsInstantiated()的Bean

    createBean: 这里逻辑相当复杂。看源码动不动会被绕进去。请甚重看源码
    1.1 确定这个Bean是否被解析
    1.2 调用第一个后置处理。这里会解析AspectJ逻辑。
    在这里插入图片描述

    1.3 instanceWrapper = createBeanInstance(beanName, mbd, args); 创建实例。
    在这里插入图片描述
    1.4 进行后置处理 @AutoWired @Value的注解的预解析
    1.5 缓存单例到三级缓存中,以防循环依赖。判断是否早期引用的Bean,如果是,则允许提前暴露引用
    判断是否能够暴露早期对象的条件:是否单例,是否允许循环依赖,是否正在创建的Bean
    如果满足这些条件就为循环依赖。调用方法回调
    1.6 属性赋值,这里会对主要就是解决循环依赖,代码解释看下面

populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)

1.7 对象初始化操作开始。protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
1.8 初始化完成返回Bean

getSingleton(String beanName, boolean allowEarlyReference): 这里是获取缓存说明一下这个方法。我上面流程图也写的很清楚
1.1 从一级缓存中拿并且查看这个Bean是否正在创建,在没有找到. 这里第一次创建肯定是没有的
1.2 从二级缓存里面拿。这里是依赖循环会有到,单例是不会有
1.3 从三级缓存。依赖循环会在三级缓存中。拿到之后通过ObjectFactory调用getObject方法的回调获取到我们一个早期对象,放入二级缓存从三级缓存中删除。
这里有一个小问题。我看了很多博客都没有特别的说明这个三级缓存是不是主要解决循环依赖。但是二级缓存和一个创建状态就已经可以解决循环依赖的,为什么还要用一个这个呢?大家可以思考一下,我个人认为是因为解耦的。评论见

populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw):
1.1 属性填充之前会校验InstantiationAwareBeanPostProcessor是否实现了这个类型接口的后置处理器。让用户可以自定义属性注入。返回值为是否继续填充Bean。return false;后面就不会继续调用任何的InstantiationAwareBeanPostProcessor
1.2 提出正常创建的循环依赖BeanWrapper对象
1.3 调用InstantiationAwareBeanPostProcessor后置处理器,从缓存拿当前解析的这个BeanWrapper的元注解数据。这里面会有一个injectedElements集合储存@AutoWired注解修饰的InjectedElement对象
1.4 通过Inject()方法递归注入。这里有两个方法重写一个是针对于@AutoWired修饰的Fiel,一个修饰Method
1.5 通过Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);获取到带注入的Bean这里通过一系列的操作最后也就是调用了getBean这种形式
1.6 利用反射调用属性赋值把Bean赋值给属性,完成循环依赖

initializeBean: 对象初始化操作:
1.1 给我们实现XXXAware接口的进行回调
1.2 调用我们的bean的后置处理器的postProcessorsBeforeInitialization方法 @PostCust注解的方法
1.3 调用初始化方法,也就是写在类中的init()
1.4 调用后置处理器。这里就是AOP和事物生成动态代理的地方

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值