源码阅读-springboot如何启动内嵌tomcat

源码阅读-springboot如何启动内嵌tomcat,第1张

源码阅读-springboot如何启动内嵌tomcat 1.实例化SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
         //资源加载器赋值
          this.resourceLoader = resourceLoader;
          //判断主类是否为空
          Assert.notNull(primarySources, "PrimarySources must not be null");
          this.primarySources = new linkedHashSet<>(Arrays.asList(primarySources));
          //根据classPath下面的类,判断是servlet还是响应式web
          this.webApplicationType = WebApplicationType.deduceFromClasspath();
          //通过SpringFactoryLoader
          setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
          //应用监听器实现类的发现,实例化以及设置
          setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
          this.mainApplicationClass = deduceMainApplicationClass();
       }
2.运行run方法,创建应用程序上下文
public ConfigurableApplicationContext run(String... args) {
          //StopWatch主要是用来统计每项任务执行时长,例如Spring Boot启动占用总时长。
          StopWatch stopWatch = new StopWatch();
          stopWatch.start();
          ConfigurableApplicationContext context = null;
          Collection exceptionReporters = new ArrayList<>();
          configureHeadlessProperty();
          //从meta-INF/spring.factories下面查找SpringApplicationRunListener.class的实现类,并进行实例化
          SpringApplicationRunListeners listeners = getRunListeners(args);
          //启动SpringApplicationRunListeners,调用了EventPublishingRunListener类的starting()方法
          listeners.starting();
          try {

             ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                   args);
             //构造容器环境,加载系统变量,环境变量,配置文件
             ConfigurableEnvironment environment = prepareEnvironment(listeners,
                   applicationArguments);
             //设置需要忽略的bean
             configureIgnoreBeanInfo(environment);
             //打印banner
             Banner printedBanner = printBanner(environment);
             //创建容器,根据webApplicationType确定容器类型
             context = createApplicationContext();
             //实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
             exceptionReporters = getSpringFactoriesInstances(
                   SpringBootExceptionReporter.class,
                   new Class[] { ConfigurableApplicationContext.class }, context);
             //准备容器 这一步主要是在容器刷新之前的准备动作。包含一个非常关键的 *** 作:将启动类注入容器,为后续开启自动化配置奠定基础。
             prepareContext(context, environment, listeners, applicationArguments,
                   printedBanner);
              //刷新容器 springBoot相关的处理工作已经结束,接下的工作就交给了spring。 内部会调用spring的refresh方法,
              //refresh方法在spring整个源码体系中举足轻重,是实现 ioc 和 aop的关键,并且注册shutdown钩子函数
             refreshContext(context);

             afterRefresh(context, applicationArguments);
             stopWatch.stop();
             if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                      .logStarted(getApplicationLog(), stopWatch);
             }
             发布应用已经启动的事件
             listeners.started(context);
             
             callRunners(context, applicationArguments);
          }
          catch (Throwable ex) {
             handleRunFailure(context, ex, exceptionReporters, listeners);
             throw new IllegalStateException(ex);
          }

          try {
             listeners.running(context);
          }
          catch (Throwable ex) {
             handleRunFailure(context, ex, exceptionReporters, null);
             throw new IllegalStateException(ex);
          }
          return context;
       }
3.在refreshContext(context);中该方法最终会调用到AbstractApplicationContext类的refresh()方法
   
@Override
       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();
             }
          }
       }
4.onRefresh()会调用到ServletWebServerApplicationContext中的onRefresh()
 @Override
       protected void onRefresh() {
          super.onRefresh();
          try {
             createWebServer();
          }
          catch (Throwable ex) {
             throw new ApplicationContextException("Unable to start web server", ex);
          }
       }


     //omcat,Jetty都实现了这个getWebServer方法,
     //我们看TomcatServletWebServerFactory中的getWebServer(ServletContextInitializer… initializers).
     private void createWebServer() {
          WebServer webServer = this.webServer;
          ServletContext servletContext = getServletContext();
          if (webServer == null && servletContext == null) {
             ServletWebServerFactory factory = getWebServerFactory();
             this.webServer = factory.getWebServer(getSelfInitializer());
          }
          else if (servletContext != null) {
             try {
                getSelfInitializer().onStartup(servletContext);
             }
             catch (ServletException ex) {
                throw new ApplicationContextException("Cannot initialize servlet context",
                      ex);
             }
          }
          initPropertySources();
       }

      ServletWebServerFactory有三个实现:
                 Jetty
                 Tomcat
                 Undertow
     @Override
       public WebServer getWebServer(ServletContextInitializer... initializers) {
          Tomcat tomcat = new Tomcat();
          File baseDir = (this.baseDirectory != null) ? this.baseDirectory
                : createTempDir("tomcat");
          tomcat.setbaseDir(baseDir.getAbsolutePath());
          Connector connector = new Connector(this.protocol);
          tomcat.getService().addConnector(connector);
          customizeConnector(connector);
          tomcat.setConnector(connector);
          tomcat.getHost().setAutoDeploy(false);
          configureEngine(tomcat.getEngine());
          for (Connector additionalConnector : this.additionalTomcatConnectors) {
             tomcat.getService().addConnector(additionalConnector);
          }
          prepareContext(tomcat.getHost(), initializers);
          return getTomcatWebServer(tomcat);
       }

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/4668708.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-11-06
下一篇2022-11-06

发表评论

登录后才能评论

评论列表(0条)

    保存