【Spring源码】2.Spring容器启动核心方法refres

2021-12-24  本文已影响0人  天还下着毛毛雨

AbstractApplicationContext

AbstractApplicationContext 是所有 Spring上下文类的抽象父类。

常见的上下文类型 :

  1. ClassPathXmlApplicationContext : xml配置的上下文类。

  2. AnnotationConfigApplicationContext : 支持注解的上下文类。构造方法里会直接传入要扫描的包路径,用于扫描该路径下,带有@Component及其派生注解的类,构造出BeanDefination注册进容器中, 后续进行实例化。

  3. AnnotationConfigEmbeddedWebApplicationContext :Springboot 1.5.x 用的,会重写refresh()方法中的onRefresh(),启动内嵌tomcat。

  4. AnnotationConfigServletWebServerApplicationContext : Springboot 2.x 用的,同样会重写refresh()方法中的onRefresh(),启动内嵌tomcat。

image

不管选用的上下文类 是哪个,都是拓展至AbstractApplicationContext类。

容器启动的核心流程都是调用的父类继承而来的refresh()。refresh()定义了一系列用来容器启动的方法, 不同的上下文类 在 核心步骤不变的情况下, 可能重写 某些个方法,来完成不同的事情,比如springboot使用的上下文类就会重写里面的onRefresh(),启动内嵌tomcat。这是一种典型的模板设计模式。

refresh()源码解析

@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      //为容器初始化做准备
      // Prepare this context for refreshing.
      prepareRefresh();

      /*
      * 1、创建BeanFactory对象
      * 2、xml解析
      *  传统标签解析:bean、import等
      *  自定义标签解析 如:<context:component-scan base-package="com.xiangxue.jack"/>
      *  自定义标签解析流程:
      *     a、根据当前解析标签的头信息找到对应的namespaceUri
      *     b、加载spring所以jar中的spring.handlers文件。并建立映射关系
      *     c、根据namespaceUri从映射关系中找到对应的实现了NamespaceHandler接口的类
      *     d、调用类的init方法,init方法是注册了各种自定义标签的解析类
      *     e、根据namespaceUri找到对应的解析类,然后调用paser方法完成标签解析
      *
      * 3、把解析出来的xml标签封装成BeanDefinition对象
      * */
      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      /*
       * 给beanFactory设置一些属性值,可以不看
       * */
      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         // 空方法
         postProcessBeanFactory(beanFactory);

         /*
          * BeanDefinitionRegistryPostProcessor
          * BeanFactoryPostProcessor
          * 完成对这两个接口的调用
          * */
         // Invoke factory processors registered as beans in the context.
         invokeBeanFactoryPostProcessors(beanFactory);

         /*
          * 把实现了BeanPostProcessor接口的类实例化,并且加入到BeanFactory中
          * */
         // Register bean processors that intercept bean creation.
         registerBeanPostProcessors(beanFactory);

         /*
          * 国际化的支持
          * */
         // Initialize message source for this context.
         initMessageSource();

         //初始化事件管理类
         // Initialize event multicaster for this context.
         initApplicationEventMulticaster();

         //这个方法着重理解模板设计模式,因为在springboot中,这个方法是用来做内嵌tomcat启动的
         // Initialize other special beans in specific context subclasses.
         onRefresh();

         /*
          * 往事件管理类中注册事件类
          * */
         // Check for listener beans and register them.
         registerListeners();

         /*
          * 这个方法是spring中最重要的方法,没有之一
          * 1、bean实例化过程
          * 2、ioc
          * 3、注解支持
          * 4、BeanPostProcessor的执行
          * 5、Aop的入口
          * */
         // Instantiate all remaining (non-lazy-init) singletons.
         finishBeanFactoryInitialization(beanFactory);

         // 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 {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
      }
   }
}
上一篇下一篇

猜你喜欢

热点阅读