美文网首页程序员spring boot源码解析
SpringBoot启动 源码深度解析(四)

SpringBoot启动 源码深度解析(四)

作者: 凡毓不凡 | 来源:发表于2020-05-09 01:09 被阅读0次

    SpringBoot 版本 : 2.2.1.RELEASE
    入口类: SpringApplication;SpringApplicationBuilder
    说明 : 由于SpringBoot建立在Spring之上,所以分析SpringBoot的启动过程其实与Spring是交错进行的,分析的时候会顺带将一些Spring的扩展点也提到
    注:本文主要讲解一些比较重要的关键步骤,不能面面俱到,若有疑问,随时保持沟通

    SpringBoot启动 源码深度解析(一)
    SpringBoot启动 源码深度解析(二)
    SpringBoot启动 源码深度解析(三)

    • 调用org.springframework.context.support.AbstractApplicationContext# registerBeanPostProcessors(beanFactory) 方法来注册拦截bean创建的处理器接着调用org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.context.support.AbstractApplicationContext) 委托方法去注册BeanPostProcessor实例
      1. 首先获取所有BeanPostProcessor类型的beanDefinetion,创建一个BeanPostProcessorChecker后置处理器,此后置处理器用来打印BeanPostProcessor处理器创建用的。
      2. 也将后置处理器分为几类:实现优先级PriorityOrdered 的、Ordered的、普通的。依次调用 getBean方法将获取的bean实例添加到bean工厂中,重要的是最后需要重新注册内部的后置处理器(实现了MergedBeanDefinitionPostProcessor接口的)
      3. 最后重新注册ApplicationListenerDetector处理器用来侦察内部的ApplicationListener监听器

    • 调用 org.springframework.context.support.AbstractApplicationContext# initMessageSource() 初始化上下文中的信息资源 .

    • 初始化上下文事件广播器ApplicationEventMulticaster从bean工厂中若加工不出来对应的bean实例,就是bean定义中没有那么会重新创建一个SimpleApplicationEventMulticaster实例).

    • 接着调用 org.springframework.context.support.AbstractApplicationContext#onRefresh() 模板方法,此处会回调ServletWebServerApplicationContextonRefresh方法

      image.png
      1. 两步操作,首先调用父类的onRefresh方法,去初始化 this.themeSource = UiApplicationContextUtils.initThemeSource(this);
      2. 然后 调用createWebServer(),此处就是创建Tomcat服务器 image.png
    • 调用 org.springframework.context.support.AbstractApplicationContext# registerListeners() 方法注册监听器对象。首先把boot配置的监听器先注册到上下文事件广播器中;然后再获取ApplicationListener类型的bean定义(部分监听器还没实例化)添加到org.springframework.context.event.AbstractApplicationEventMulticaster.ListenerRetriever#applicationListenerBeans属性中;最后发布早批注册的监听事件通知监听器。

    • 调用 finishBeanFactoryInitialization 方法实例化非延迟加载的单例bean对象,即初始化bean工厂。其中会判定是否有属性解析器,没有会从environment中获取并添加到bean工厂中。设置临时类加载器会空,设置bean定义配置冻结标志为true,将beanDefinitionNames放入到冻结数组frozenBeanDefinitionNames中。最后实例化所有的非延迟化单例对象。

      image.png
      1. 👍👍进入到方法👍👍org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons中,使用局部变量保存之前定义的bean名称,然后遍历所有的对象,依次判断。
      1. 👍👍首先获取bean定义,若不是抽象类并且是单例对象并且不需要延迟初始化的bean名称,紧接着判断是否是工厂bean,若不是工厂bean,则直接调用getBean(benaName)方法实例化bean定义;若是工厂bean,则需要先在bean名称前面加上 & 符号再调用getBean(benaName)方法,再判断获取的bean实例是否是 FactoryBean类型,若是并且没有设置安全security检查,获取是否需要急切初始化的布尔值赋给变量eagerInit,若为true,则也需要调用getBean的方法。即如果是工厂bean则需要判断需要急切初始化参数值,若为true则表示工厂bean也需要初始化,否则不需要调用getBean方法 :
        2.1. getBean() -> doGetBean() -> 进入方法。首先获取转换之后的bean名称(不包含或者去除factoryBean的前缀 & 之后的名称),调用 getSingleton(beanName)方法检查当前名称是否是早期注册的单例实例,先从singletonObjects(一级缓存) 缓存Map中获取,若没有并且单例实例正在创建中,则从 earlySingletonObjects(二级缓存)中获取单例实例,若以然为空,但是允许早期引用为true,则从 singletonFactory 单例工厂(三级缓存)中获取实例, 然后将获取的单例实例放入到 earlySingletonObjects二级缓存)中,并且从单例工厂中(三级缓存)移除。 👍:singletonObjects 中若没有并且单例正在初始化 ** -> earlySingletonObjects 若没有并且允许早期暴漏引用 -> singletonFactories 若没有,则返回空,若有对应的工厂去处理,则获取工厂的getObject()对象,放入到 earlySingletonObjects ,同时从 singletonFactories 中移除当前bean名称。 👍
        2.2. 若获取的实例不为空,调用
        org.springframework.beans.factory.support.AbstractBeanFactory#
        getObjectForBeanInstance() 获取当前bean实例。如果当前bean名称间接引用了工厂(名称以&)但不是 FactoryBean类型,则抛BeanIsNotAFactoryException异常。即 禁止&开头的非FactoryBean类型的bean
        2.3. 若当前bean不是工厂bean 或者名称以&开头,则直接返回实例;否则说明是工厂bean,则先从缓存 factoryBeanObjectCache 中获取bean实例,若缓存中不存在,将当前对象实例转换成FactoryBean类型,然后调用 org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean 从 FactoryBean中获取bean实例。
        2.4. 进到方法,若工厂是单例并且bean名称在单例bean定义(一级缓存)中则首先尝试从 factoryBeanObjectCache 缓存Map中获取对应的实例。若没有,调用 org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean,进入到方法发现调用的是 object = factory.getObject()获取的对象。所以:工厂bean 获取实例时调用对应的getObject方法返回的实例。再次检查 factoryBeanObjectCache缓存中是否有对应的实例(此处再次检查是因为可能存在循环引用处理出发了自定义getBean()的调用)。若缓存中有,直接赋值给要返回的对象 object;若没有则判断是否应该执行后处理,org.springframework.beans.factory.support.FactoryBeanRegistrySupport#postProcessObjectFromFactoryBean(),然后进入到 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization()方法,执行bean初始化之后的后处理操作。获取所有的BeanPostProcessor调用其 postProcessAfterInitialization(Object bean, String beanName)方法,👍此处可以实现对初始化的bean实例进行修改👍。
        2.5. 若调用 Object sharedInstance = getSingleton(beanName) 返回的bean实例为空,校验若是prototype类型,则抛异常; 检查parentBeanFactory工厂中是否存在bean定义,若父工厂不为空,并且子工厂中不包含bean定义,则从父工厂中搜索bean实例。然后调用 String[] dependsOn = mbd.getDependsOn(); 获取bean定义所依赖的所有bean名称,确保当前bean依赖的bean已经初始化(即初始化时先初始化依赖的bean).
        2.6. 然后调用 getBean(dep)先行初始化依赖的bean的实例,重复上述步骤,重新获取bean实例等等。。。
        2.7. 接着判断当前实例若是单例模式,首先调用org.springframework.beans.factory.support.AbstractBeanFactory#createBean方法 -> org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean 方法,进入方法中,首先调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation 此处会先① 执行实例化前得操作,org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance方法创建实例包装对象,然后调用 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#② applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName) 允许后置处理器修改被合并得bean定义,bean定义处理之后设置为true。然后判断bean定义如果是单例对象并且允许循环引用,执行代码addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));解决循环引用, image.png 首先执行getEarlyBeanReference方法,允许暴漏早期引用,方法里面首先获取所有得BeanPostProcessor,判断若是 SmartInstantiationAwareBeanPostProcessor类型,则回调后置处理器得子类实现方法org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(Object bean, String beanName)
        如果单例对象缓存中不存在bean名称得话,将bean名称跟早期暴漏对象工厂添加到单例工厂 singletonFactories(三级缓存)与 已经注册得单例缓存registeredSingletons 中,同时移除earlySingletonObjects (二级缓存)
        2.8. 然后调用 populateBean(beanName, mbd, instanceWrapper);填充Bean属性,首先判断实例化后置处理器标志 hasInstantiationAwareBeanPostProcessors 若为true,则循环回调 InstantiationAwareBeanPostProcessor实例得 ③ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)方法,
        执行实例化后处理
        。若方法返回为false,则结束属性填充。
        2.9. 接着判断属性注入类型若是根据名称注入 AUTOWIRE_BY_NAME,则调用 autowireByName(beanName, mbd, bw, newPvs)填充属性;若是根据类型注入 AUTOWIRE_BY_TYPE,则调用 autowireByType(beanName, mbd, bw, newPvs) 方法完成注入: image.png
        2.10. 进入方法 autowireByName,首先获取所有属性名称,然后循环判断属性,若在bean定义中并且是工厂bean则返回true,然后执行getBean得操作,然后调用 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#registerDependentBean(String beanName, String dependentBeanName) 方法执行依赖bean得注册;若bean定义中没有或者不是工厂bean,则返回false,不做处理。同理调用 autowireByType 方法。
        2.11. 接着循环遍历已经注册得BeanPostProcessors后置处理器,若是 InstantiationAwareBeanPostProcessor 类型,则首先调用后置处理器得 postProcessProperties方法,此处会处理内置得用来处理
        @Autowired
        得后置处理器 AutowiredAnnotationBeanPostProcessor 和 用来处理@PostConstruct@PreDestroy 得后置处理器CommonAnnotationBeanPostProcessor
        2.12. 进入 AutowiredAnnotationBeanPostProcessor 得回调方法 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties(PropertyValues pvs, Object bean, String beanName)中,首先调用方法 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata找到自动注入得元数据;然后调用org.springframework.beans.factory.annotation.InjectionMetadata#inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs),然后判断isField若为true,则反射调用Field得set方法为成员设置值,否则反射调用Method得invoke方法为方法设置值;最后若属性值不为空,则调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs),此方法会将属性值转化后填充到BeanWrapper中。
        2.13. 然后调用 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)方法对以下三种bean实例进行回调(BeanNameAwareBeanClassLoaderAwareBeanFactoryAware),然后再调用BeanPostProcessor得初始化前方法 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)对bean进行初始化前回调,④ 允许初始化前修改;紧接着调用初始化方法:优先调用 InitializingBean类型得afterPropertiesSet初始化方法,再调用initMethod方法,最后调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#⑤ applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)对bean进行初始化后处理

      总结doCreateBean()得逻辑:createInstance 创建bean实例-> populateBean 填充bean属性-> initializeBean 回调bean调用aware得set回调方法、调用后置处理器得初始化前得回调方法 postProcessBeforeInitialization()、调用 InitializingBean得afterPropertiesSet()初始化回调方法、调用 initMethod()回调方法、最后调用 后置处理器得 postProcessAfterInitialization()回调方法)

      1. 👍👍最后遍历所有的bean定义,调用 getSingleton(beanName) 获取单例实例,判断当前单例实例若是 SmartInitializingSingleton 类型,则需要会调afterSingletonsInstantiated()方法,否则不做处理。
    • 最后调用 org.springframework.context.support.AbstractApplicationContext#finishRefresh()方法完成刷新,首先调用子类得实现方法org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#finishRefresh子类首先调用父类得finishRefresh之后执行:

      • 清理缓存
      • 初始化声明周期 LifecycleProcessor处理器,设置启动状态为running
      • 发布上下文刷新事件

      然后再调用org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#startWebServer开启Tomcat服务,成功开启之后发布一个 ServletWebServerInitializedEvent事件。

    • 最后如果启动出现异常,销毁单例bean,清空所有相关得缓存,取消刷新(设置激活状态为false),将异常抛给调用者;若启动成功,清空相关得缓存。

    文章要是勘误或者知识点说的不正确,欢迎评论,毕竟这也是作者通过阅读源码获得的知识,难免会有疏忽!

    相关文章

      网友评论

        本文标题:SpringBoot启动 源码深度解析(四)

        本文链接:https://www.haomeiwen.com/subject/tsrqnhtx.html