SpringBoot学习之路---简单记录嵌入式Servlet容器的启动原理

在我的上一篇博客中简单记录了SpringBoot嵌入式Servlet容器是如何实现自动配置的,并且如何读取我们自己编写的Customizer,这一篇博客来介绍一下这个嵌入式Servlet容器是如何启动的,并且联动之前的博客,来说明一下整个SpringBoot项目是如何跑起来的。


这一篇博客与上一篇嵌入式自动配置的博客关系比较大,合起来可以大致明白整个SpringBoot项目的嵌入式Servlet容器的启动原理和自动配置生效原理,大家如果感兴趣的话可以翻看一下我之前的博客哦。接下来进入正题。

Springboot项目要启动,那就要运行主程序类中的run()方法,我们点进去看一下,里面有几个方法值得关注:

protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch(this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                    break;
                case REACTIVE:
                    contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                    break;
                default:
                    contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
                }
            } catch (ClassNotFoundException var3) {
                throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
            }
        }

        return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
    }

createApplicationContext:观看它的源码,可以看到里面有个switch语句,里面根据当前应用是什么类型,而来创建什么样的IOC容器,如果是web应用,则创建AnnotationConfigServletWebServerApplicationContext类型的IOC容器,反之则创建AnnotationConfigApplicationContext类型的IOC容器

在run方法内还有一个方法:refreshContext(context)

private void refreshContext(ConfigurableApplicationContext context) {
        this.refresh(context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            } catch (AccessControlException var3) {
            }
        }

    }

该方法的作用是创建IOC容器对象,并初始化容器,创建容器中的每一个组件

再点进去,发现refresh方法,它是一个接口

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);

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

         // Invoke factory processors registered as beans in the context.
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         registerBeanPostProcessors(beanFactory);

         // Initialize message source for this context.
         initMessageSource();

         // Initialize event multicaster for this context.
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         onRefresh();

         // Check for listener beans and register them.
         registerListeners();

         // 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();
      }
   }
}

里面有一个onfresh()方法,那么就要去找它的实现类了,这个实现类其实就是我们刚刚创建的web应用的IOC容器,它重写了onfresh()方法。这里其实就是个面向接口编程的思想,如果当前不是web应用,那么它就执行默认的ioc容器内的onfresh方法

而webioc容器内部会创建嵌入式的Servlet容器createEmbeddedServletContainer();

又在这个方法的内部有一行:

EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();

看方法名,可以得出,获取嵌入式的Servlet容器工厂。它是直接从容器中获取对象,之后的步骤就和之前的博客连接起来了,这里以tomcat为例,SpringBoot会根据引入的依赖从而选择Tomcat的嵌入式工厂,并把它放到容器中。上文提到的后置处理器一看是这个对象,就获取所有的定制器来先定制Servlet容器的相关配置;

之后会执行到这条语句

this.embeddedServletContainer = containerFactory      .getEmbeddedServletContainer(getSelfInitializer());

调用工厂中的方法,从而获取到嵌入式Servlet容器。

最终嵌入式的Servlet容器创建对象并启动Servlet容器。

之后refresh方法会继续执行,再将IOC容器中的其他组件创建出来。

发布了39 篇原创文章 · 获赞 47 · 访问量 7978

猜你喜欢

转载自blog.csdn.net/Jokeronee/article/details/105248879