IOC容器核心流程

Posted 踩踩踩从踩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IOC容器核心流程相关的知识,希望对你有一定的参考价值。

前言

本篇文章主要讲解的是spring中ioc容器的核心流程,而Spring IOC容器核心方法在于 Refresh 方法,这个方法里面完成了 Spring 初始化、准备Bean、实例化Bean及扩展功能的实现。因此最重要以及重要的地方就是refresh方法,资源的加载,以及各种扩展功能等等。

Refresh方法

ConfigurableApplicationContext#refresh 中进行定义

这个方法用来加载刷新配置,这些配置可能来自, java 配置、 xml 文件、 properties 文件,关系型 数据库,或者其他格式。 作为一个启动方法,它应当在初始化失败后销毁已经创建了的单例,防止占着资源不用。也就是说 调用这个方法,要么没有所有的单例被创建、要么没有没有单例对象创建。

经过对该方法的注解解读,发现该方法提供了从加载配置单例bean创建的功能。

这个方法用来加载刷新配置,这些配置可能来自, java 配置、 xml 文件、 properties 文件, 关系型数据库,或者其他格式。 作为一个启动方法,它应当在初始化失败后销毁已经创建了的单例,防止占着资源不用。 也就是说调用这个方法,要么没有所有的单例被创建、要么没有没有单例对象创建。

AbstractApplicationContext#refresh 实现

public void refresh() throws BeansException, IllegalStateException  
        synchronized (this.startupShutdownMonitor)  
        //1 Prepare this context for refreshing. 
        prepareRefresh();
        //2 Tell the subclass to refresh the internal bean factory.
         // 为什么要从子类获得刷新后的BeanFactory? 
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 
        //3 Prepare the bean factory for use in this context.                 
         prepareBeanFactory(beanFactory); 
        try 
            //4 Allows post-processing of the bean factory in context subclasses. 
            postProcessBeanFactory(beanFactory);
             //5 Invoke factory processors registered as beans in the context. 
             invokeBeanFactoryPostProcessors(beanFactory); 
            //6 Register bean processors that intercept bean creation. 
             registerBeanPostProcessors(beanFactory); 
            //7 Initialize message source for this context. 
             initMessageSource(); 
            //8 Initialize event multicaster for this context. 
             initApplicationEventMulticaster(); 
            //9 Initialize other special beans in specific context subclasses. 
              onRefresh(); 
           //10 Check for listener beans and register them.
            registerListeners(); 
          //11 Instantiate all remaining (non-lazy-init) singletons. 
             finishBeanFactoryInitialization(beanFactory); 
           //12 Last step: publish corresponding 
           event. finishRefresh(); 
         catch (BeansException ex)  
              if (logger.isWarnEnabled())  
                    logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex);
               
              // Destroy already created singletons to avoid dangling resources. 
              destroyBeans(); 
            // Reset 'active' flag. 
              cancelRefresh(ex); 
            // Propagate exception to caller. throw ex; 
          

          finally 
          //13 Reset common introspection caches in Spring's core, since we 
        // might not ever need metadata for singleton beans anymore... resetCommonCaches(); 
        
      
AbstractApplicationContext 中的实现,调用了 10 多个方法,来完成该功能。 用来启动和关闭的方法  startupShutdownMonitor 对象。 里面很多方法,都是protected的,因此只能子类进行访问, 例如preparerefresh方法  这些 对于外部是不可知的。

 在refresh方法中做的操作 

刷新前置的准备  环境属性的添加  然后初始化一些事件监听器列表等等。

 

 整个流程如上图,其中最关键的在于下面的6个方法。

obtainFreshBeanFactory

告诉子类刷新内部的 BeanFactory ,其实就是配置用户属性、加载 Bean 定义,并返回刷新后的 Bean 工厂。prepareBeanFacotry 方法又由两个抽象方法构成,交给子类实现。也就是子类必定含有一个BeanFactory实例,并且还需要提供刷新方法、返回 BeanFactory 实例方法。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory()  
    refreshBeanFactory(); 
    return getBeanFactory();
 

这里的刷新bean工厂, 一定要重新加载bean定义, bean定义的对象。

 对应的实现有AbstractRefreshableApplicationContextGenericApplicationContext两个类。

AbstractRefreshableApplicationContext

AbstractRefreshableApplicationContext 中实现的刷新方法,可以被多次调用执行。
  • 自定义Bean工厂属性:Bean定义重写、循环引用等配置
  • 创建DefalutListableBeanFactory实例
  • 设置ID  
  • 等待子类实现的,向bean工厂注册Bean定义
  • 持有bean工厂实例,以便在getBeanFactory方法中返回出去
bean 定义的加载注册 Spring中Bean定义加载过程解析_踩踩踩从踩的博客-CSDN博客

GenericApplicationContext

GenericApplicationContext中的刷新方法,只能被调用一次,被Atomicrefreshed状态控制着。

 刷新的方法也很简单,只是设置了一个ID

BeanFactory 在构造函数中创建的。 Bean 定义加载过程都装载了什么。 BeanFactoryPostProcessor 、 BeanPostProcessor、 ApplicationListener

prepareBeanFacotry

此时, Bean 定义加载完成, Bean 工厂已经被构建了,加下来做的事情就是给 Bean 工厂对象,注入执行后续东西需要的依赖,比如ClassLoader BeanPostProcessor 、环境相关的实例 Bean
  • 给bean工作准备ClassLoader、SPL表达是解析器、属性编辑注册器等
  • 向BeanFactory注册ApplicationContextAwareProcessor
  • 依赖需要使用的bean,IOC容器自己的多角色身份 @Autowried方式获得下列类型bean
  • 注入ApplicationListeners接口实现的发现处理器,同时带有销毁、bean定义混合的实现。
  • 操作系统环境变量:JAVA_HOME等

 BeanPostProcessor的注入

ApplicationContextAwareProcessor ApplicationListenerDetector 、LoadTimeWeaverAwareProcessor,查看其中一个。 ApplicationContextAwareProcessor 中的实现 只针对EnvironmentAware、EmbeddedValueResolverAware、 ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、 ApplicationContextAware 6种实现进行处理。

 

手动注册环境相关单例 Bean environment systemProperties systemEnvironment

 

 invokeBeanFactoryPostProcessors

bean 工厂基本准备已经完成,但是 Bean 实例还未进行初始化,接下来,调用 BeanFactoryPostProcessor Bean 工厂中的 Bean 定义进行调整。 最重要的处理在委托里面实现  getBeanFactoryPostProcessors()获取的是容器里面的列表属性,这个属性没有机会给外部去 注入BeanFactoryPostProcessor对象。因为ApplicationContext子类在构造函数中调用了refresh方 法。所以这里是个空值。

 

 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法解读

 BeanFactoryPostProcessor与容器

 BeanFactoryPostProcessors的调用处理

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 分析 拆分处理: registryProcessors regularPostProcessors 排序处理: PriorityOrdered Ordered 多次调用 BeanFactoryPostProcessors 的分析:在调用 BeanFactoryPostProcessors 过程中,还会 产生 BeanFactoryPostProcessors ,直到所有的 BeanFactoryPostProcessors 处理完毕。

registerBeanPostProcessors

此时 Bean 定义加载完成, Bean 工厂完成了刷新实例化,通过了 BeanFactoryProcessor 修整了 Bean 定义,接下来注册BeanPostProcessors

 PostProcessorRegistrationDelegate.registerBeanPostProcessors

注册 BeanPostProcessor 的处理 整体处理逻辑与 BeanFactroyPostProcessor 的处理一样,排序然后调用的处理。 1. priorityOrderedPostProcessors 2. orderedPostProcessors 3. nonOrderedPostProcessors 4. internalPostProcessors 5. ApplicationListenerDetector

initMessageSource

 此时BenPostProcessor都已经注册完成,下一步准备资源国际化的事宜。

如果Bean工厂中存在名为messageSource的bean,则使用它 使用DelegatingMessageSource作为国际化资源处理bean

 registerListeners

 国际化资源准备完毕,接下来,检查事件监听器,并注册到事件传播器上。在不生成Bean对象的情况下添加ApplicationListener bean作为监听器

 

这两种去获取 beanfactory的方式。  效果都是一样的。

事件广播器执行方法 SimpleApplicationEventMulticaster#multicastEvent(ApplicationEvent, ResolvableType)

 

 finishBeanFactoryInitialization

完成 bean 工厂的初始化,将 bean 工厂中,非懒加载的单例 bean 进行实例化。

 

finishRefresh

 

 容器的关闭

AbstractApplicationContext#close AbstractApplicationContext#registerShutdownHook AbstractApplicationContext#doClose

 

以上是关于IOC容器核心流程的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码剖析1:初探Spring IOC核心流程

Spring IOC容器初始化流程源码分析

Spring IOC容器初始化流程源码分析

springboot启动流程ioc容器refresh过程(上篇)

Spring IOC容器核心流程源码分析

深入浅出Spring原理及实战「原理分析专题」不看源码就带你剖析IOC容器核心流程以及运作原理