欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

ServletWebServerApplicationContext创建Web容器Tomcat示例,

来源: javaer 分享于  点击 214 次 点评:178

ServletWebServerApplicationContext创建Web容器Tomcat示例,


目录
  • 正文
  • 创建Web服务
  • 一、获取Web服务器工厂
    • 1.1 选择导入Web工厂
  • 二、getWebServer:获取Web服务
    • 2.1 创建TomcatEmbeddedContext
    • 2.2. 创建TomcatWebServer
      • 2.2.1 启动Tomcat
    •  初始化小结
      • startInternal:启动Internal
      • NamingResources启动
      • Service启动
      • 启动Engine
      •  启动TomcatEmbeddedContext
      • 启动Executor
      • 启动MapperListener
      •  启动Connector
    •  启动总结
    • 三、注册Bean生命周期
      • 3.1 WebServerStartStopLifecycle(Web服务器启动-停止生命周期)
        • 3.1.1 addPreviouslyRemovedConnectors:启动Connector
    • 四、初始化上下文环境

      正文

      ServletWebServerApplicationContext实现了父类AbstractApplicationContext的onRefresh模板方法,在这里进行了拓展创建了Web容器。

      @Override
      protected void onRefresh() {
         super.onRefresh();
         try {
            createWebServer();
         }
         catch (Throwable ex) {
            throw new ApplicationContextException("Unable to start web server", ex);
         }
      }
      

      创建Web服务

      private void createWebServer() {
         WebServer webServer = this.webServer;
         ServletContext servletContext = getServletContext();
         if (webServer == null && servletContext == null) {
            //一、获取Web服务器工厂
            ServletWebServerFactory factory = getWebServerFactory();
            //二、获取Web服务
            this.webServer = factory.getWebServer(getSelfInitializer());
            //三、注册Bean生命周期(在容器启动和销毁时调用)
            getBeanFactory().registerSingleton("webServerGracefulShutdown",
                  new WebServerGracefulShutdownLifecycle(this.webServer));
            getBeanFactory().registerSingleton("webServerStartStop",
                  new WebServerStartStopLifecycle(this, this.webServer));
         }
         else if (servletContext != null) {
            try {
               getSelfInitializer().onStartup(servletContext);
            }
            catch (ServletException ex) {
               throw new ApplicationContextException("Cannot initialize servlet context", ex);
            }
         }
         //四、初始化上下文环境
         initPropertySources();
      }
      

      一、获取Web服务器工厂

      protected ServletWebServerFactory getWebServerFactory() {
         // Use bean names so that we don't consider the hierarchy
         //获取Web服务器工厂名称
         String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
         if (beanNames.length == 0) {
            throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing "
                  + "ServletWebServerFactory bean.");
         }
         if (beanNames.length > 1) {
            throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "
                  + "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
         }
         //从容器中获取Web服务器工厂实例
         return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
      }
      

      这里的Web服务器工厂是通过ServletWebServerFactoryAutoConfiguration自动配置类导入进来的。

      @Configuration(proxyBeanMethods = false)
      @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
      @ConditionalOnClass(ServletRequest.class)
      //Web启动环境
      @ConditionalOnWebApplication(type = Type.SERVLET)
      @EnableConfigurationProperties(ServerProperties.class)
      //2.1导入Web工厂
      @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
            ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
            ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
            ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
      public class ServletWebServerFactoryAutoConfiguration {
         //导入Web服务器工厂自定义程序
         @Bean
         public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
            return new ServletWebServerFactoryCustomizer(serverProperties);
         }
         //如果是Tomcat则导入Tomcat自定义程序
         @Bean
         @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
         public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
               ServerProperties serverProperties) {
            return new TomcatServletWebServerFactoryCustomizer(serverProperties);
         }
         @Bean
         @ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class)
         @ConditionalOnProperty(value = "server.forward-headers-strategy", havingValue = "framework")
         public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
            ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
            FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter);
            registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);
            registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
            return registration;
         }
         /**
          * Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via
          * {@link ImportBeanDefinitionRegistrar} for early registration.
          */
         public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
            private ConfigurableListableBeanFactory beanFactory;
            @Override
            public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
               if (beanFactory instanceof ConfigurableListableBeanFactory) {
                  this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
               }
            }
            @Override
            public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                  BeanDefinitionRegistry registry) {
               if (this.beanFactory == null) {
                  return;
               }
               registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
                     WebServerFactoryCustomizerBeanPostProcessor.class);
               registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
                     ErrorPageRegistrarBeanPostProcessor.class);
            }
            private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {
               if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
                  RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
                  beanDefinition.setSynthetic(true);
                  registry.registerBeanDefinition(name, beanDefinition);
               }
            }
         }
      }
      

      1.1 选择导入Web工厂

      @Configuration
      class ServletWebServerFactoryConfiguration {
          ServletWebServerFactoryConfiguration() {
          }
          //1.如果容器中有Servlet,Undertow,SslClientAuthMode就会创建Undertow工厂
          @Configuration
          @ConditionalOnClass({Servlet.class, Undertow.class, SslClientAuthMode.class})
          @ConditionalOnMissingBean(
              value = {ServletWebServerFactory.class},
              search = SearchStrategy.CURRENT
          )
          public static class EmbeddedUndertow {
              public EmbeddedUndertow() {
              }
              @Bean
              public UndertowServletWebServerFactory undertowServletWebServerFactory() {
                  return new UndertowServletWebServerFactory();
              }
          }
          //2.如果容器中有Servlet,Server,Loader就会创建Jetty工厂
          @Configuration
          @ConditionalOnClass({Servlet.class, Server.class, Loader.class, WebAppContext.class})
          @ConditionalOnMissingBean(
              value = {ServletWebServerFactory.class},
              search = SearchStrategy.CURRENT
          )
          public static class EmbeddedJetty {
              public EmbeddedJetty() {
              }
              @Bean
              public JettyServletWebServerFactory JettyServletWebServerFactory() {
                  return new JettyServletWebServerFactory();
              }
          }
          //3.如果容器中有Servlet,Tomcat,UpgradeProtocol就会创建Tomcat工厂
          @Configuration
          @ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class})
          @ConditionalOnMissingBean(
              value = {ServletWebServerFactory.class},
              search = SearchStrategy.CURRENT
          )
          public static class EmbeddedTomcat {
              public EmbeddedTomcat() {
              }
              @Bean
              public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
                  return new TomcatServletWebServerFactory();
              }
          }
      }
      

      二、getWebServer:获取Web服务

      public static final String DEFAULT_PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol";
      private String protocol = DEFAULT_PROTOCOL;
      public WebServer getWebServer(ServletContextInitializer... initializers) {
          Tomcat tomcat = new Tomcat();
          // 给嵌入式Tomcat创建一个临时文件夹,用于存放Tomcat运行中需要的文件
          File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
          tomcat.setBaseDir(baseDir.getAbsolutePath());
          // Tomcat核心概念:Connector,默认放入的protocol为NIO模式
          Connector connector = new Connector(this.protocol);
          // 给Service添加Connector
          tomcat.getService().addConnector(connector);
          // 执行定制器,修改即将设置到Tomcat中的Connector
          customizeConnector(connector);
          tomcat.setConnector(connector);
          // 关闭热部署(嵌入式Tomcat不存在修改web.xml、war包等情况)
          tomcat.getHost().setAutoDeploy(false);
          // 设置backgroundProcessorDelay机制
          configureEngine(tomcat.getEngine());
          for (Connector additionalConnector : this.additionalTomcatConnectors) {
              tomcat.getService().addConnector(additionalConnector);
          }
          // 2.1 创建TomcatEmbeddedContext
          prepareContext(tomcat.getHost(), initializers);
          // 2.2. 创建TomcatWebServer
          return getTomcatWebServer(tomcat);
      }
      

      2.1 创建TomcatEmbeddedContext

      (注释均已在源码中标注好,小伙伴们对哪一步感兴趣可以借助IDE自己动手Debug体会一下实现)

      protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
          File documentRoot = getValidDocumentRoot();
          // 创建TomcatEmbeddedContext
          TomcatEmbeddedContext context = new TomcatEmbeddedContext();
          if (documentRoot != null) {
              context.setResources(new LoaderHidingResourceRoot(context));
          }
          context.setName(getContextPath());
          context.setDisplayName(getDisplayName());
          // 设置contextPath,很熟悉了
          context.setPath(getContextPath());
          // 给嵌入式Tomcat创建docbase的临时文件夹
          File docBase = (documentRoot != null) ? documentRoot : createTempDir("tomcat-docbase");
          context.setDocBase(docBase.getAbsolutePath());
          // 注册监听器
          context.addLifecycleListener(new FixContextListener());
          context.setParentClassLoader((this.resourceLoader != null) ? this.resourceLoader.getClassLoader()
                  : ClassUtils.getDefaultClassLoader());
          // 设置默认编码映射
          resetDefaultLocaleMapping(context);
          addLocaleMappings(context);
          context.setUseRelativeRedirects(false);
          try {
              context.setCreateUploadTargets(true);
          }
          catch (NoSuchMethodError ex) {
              // Tomcat is &lt; 8.5.39. Continue.
          }
          configureTldSkipPatterns(context);
          // 自定义的类加载器,可以加载web应用的jar包
          WebappLoader loader = new WebappLoader(context.getParentClassLoader());
          loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName());
          // 指定类加载器遵循双亲委派机制
          loader.setDelegate(true);
          context.setLoader(loader);
          // 注册默认的Servlet
          if (isRegisterDefaultServlet()) {
              addDefaultServlet(context);
          }
          // 如果需要jsp支持,注册jsp的Servlet和Initializer
          if (shouldRegisterJspServlet()) {
              addJspServlet(context);
              addJasperInitializer(context);
          }
          // 注册监听器
          context.addLifecycleListener(new StaticResourceConfigurer(context));
          ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
          host.addChild(context);
          configureContext(context, initializersToUse);
          postProcessContext(context);
      }
      

      2.2. 创建TomcatWebServer

      protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
         return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
      }
      

      进入TomcatWebServer构造方法中:

      public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
          Assert.notNull(tomcat, "Tomcat Server must not be null");
          this.tomcat = tomcat;
          this.autoStart = autoStart;
          //初始化服务
          initialize();
      }
      

      初始化TomcatWebServer

      private void initialize() throws WebServerException {
         logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
         synchronized (this.monitor) {
            try {
               //设置Engine的id
               addInstanceIdToEngineName();
               //获取Context(TomcatEmbeddedContext  2.1中创建出来的)
               Context context = findContext();
               //添加监听器 TomcatEmbeddedContext
               //在服务启动时如果有连接进来先删除连接,以便在启动服务时不会发生协议绑定。
               context.addLifecycleListener((event) -> {
                  if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
                     // Remove service connectors so that protocol binding doesn't
                     // happen when the service is started.
                     //删除ServiceConnectors,以便在启动服务时不会发生协议绑定。
                     removeServiceConnectors();
                  }
               });
               // Start the server to trigger initialization listeners
               //2.2.1 启动Tomcat
               this.tomcat.start();
               // We can re-throw failure exception directly in the main thread
               //Tomcat启动有异常需要在主线程中抛出
               rethrowDeferredStartupExceptions();
               try {
                  ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
               }
               catch (NamingException ex) {
                  // Naming is not enabled. Continue
               }
               // Unlike Jetty, all Tomcat threads are daemon threads. We create a
               // blocking non-daemon to stop immediate shutdown
               //开启阻塞非守护线程停止web容器
               startDaemonAwaitThread();
            }
            catch (Exception ex) {
               stopSilently();
               destroySilently();
               throw new WebServerException("Unable to start embedded Tomcat", ex);
            }
         }
      }
      

      2.2.1 启动Tomcat

      创建和初始化Server和Service

      public void start() throws LifecycleException {
          //创建服务(Server和Service)
          getServer();
          server.start();
      }
      

      启动服务

      public final synchronized void start() throws LifecycleException {
          //如果是正在启动或启动状态
          if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
                  LifecycleState.STARTED.equals(state)) {
              if (log.isDebugEnabled()) {
                  Exception e = new LifecycleException();
                  log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
              } else if (log.isInfoEnabled()) {
                  log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
              }
              return;
          }
          //如果是新建状态
          if (state.equals(LifecycleState.NEW)) {
              //2.2.1.1 初始化服务
              init();
          //如果是失败状态    
          } else if (state.equals(LifecycleState.FAILED)) {
              //停止服务
              stop();
          //如果不是初始化也不是停止状态
          } else if (!state.equals(LifecycleState.INITIALIZED) &amp;&amp;
                  !state.equals(LifecycleState.STOPPED)) {
              //修改状态
              invalidTransition(Lifecycle.BEFORE_START_EVENT);
          }
          try {
              //修改状态为准备启动
              setStateInternal(LifecycleState.STARTING_PREP, null, false);
              //2.2.1.2 启动Internal
              startInternal();
              if (state.equals(LifecycleState.FAILED)) {
                  // This is a 'controlled' failure. The component put itself into the
                  // FAILED state so call stop() to complete the clean-up.
                  stop();
              } else if (!state.equals(LifecycleState.STARTING)) {
                  // Shouldn't be necessary but acts as a check that sub-classes are
                  // doing what they are supposed to.
                  invalidTransition(Lifecycle.AFTER_START_EVENT);
              } else {
                  setStateInternal(LifecycleState.STARTED, null, false);
              }
          } catch (Throwable t) {
              // This is an 'uncontrolled' failure so put the component into the
              // FAILED state and throw an exception.
              handleSubClassException(t, "lifecycleBase.startFail", toString());
          }
      }
      

      2.2.1.1 初始化Server

      public final synchronized void init() throws LifecycleException {
          if (!state.equals(LifecycleState.NEW)) {
              invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
          }
          try {
              //设置状态为初始化
              setStateInternal(LifecycleState.INITIALIZING, null, false);
              //初始化
              initInternal();
              //设置状态为初始化完成
              setStateInternal(LifecycleState.INITIALIZED, null, false);
          } catch (Throwable t) {
              handleSubClassException(t, "lifecycleBase.initFail", toString());
          }
      }
      

      初始化 Server

      protected void initInternal() throws LifecycleException {
          //调用父类初始化(设置名称:Tomcat,类型:Server)
          super.initInternal();
          // Initialize utility executor
          reconfigureUtilityExecutor(getUtilityThreadsInternal(utilityThreads));
          //注册线程池
          register(utilityExecutor, "type=UtilityExecutor");
          // Register global String cache
          // Note although the cache is global, if there are multiple Servers
          // present in the JVM (may happen when embedding) then the same cache
          // will be registered under multiple names
          //注册字符串缓存
          onameStringCache = register(new StringCache(), "type=StringCache");
          // Register the MBeanFactory
          MBeanFactory factory = new MBeanFactory();
          factory.setContainer(this);
          //注册Bean工厂
          onameMBeanFactory = register(factory, "type=MBeanFactory");
          // Register the naming resources
          //注册命名资源
          globalNamingResources.init();
          // Populate the extension validator with JARs from common and shared
          // class loaders
          if (getCatalina() != null) {
              ClassLoader cl = getCatalina().getParentClassLoader();
              // Walk the class loader hierarchy. Stop at the system class loader.
              // This will add the shared (if present) and common class loaders
              while (cl != null &amp;&amp; cl != ClassLoader.getSystemClassLoader()) {
                  if (cl instanceof URLClassLoader) {
                      URL[] urls = ((URLClassLoader) cl).getURLs();
                      for (URL url : urls) {
                          if (url.getProtocol().equals("file")) {
                              try {
                                  File f = new File (url.toURI());
                                  if (f.isFile() &amp;&amp;
                                          f.getName().endsWith(".jar")) {
                                      ExtensionValidator.addSystemResource(f);
                                  }
                              } catch (URISyntaxException e) {
                                  // Ignore
                              } catch (IOException e) {
                                  // Ignore
                              }
                          }
                      }
                  }
                  cl = cl.getParent();
              }
          }
          // Initialize our defined Services
          //2.2.1.1.1 初始化service(2.2.1最开始时创建)
          for (Service service : services) {
              service.init();
          }
      }
      

      初始化Service

      public final synchronized void init() throws LifecycleException {
          if (!state.equals(LifecycleState.NEW)) {
              invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
          }
          try {
              //设置状态为初始化
              setStateInternal(LifecycleState.INITIALIZING, null, false);
              //初始化
              initInternal();
              //设置状态为初始化完成
              setStateInternal(LifecycleState.INITIALIZED, null, false);
          } catch (Throwable t) {
              handleSubClassException(t, "lifecycleBase.initFail", toString());
          }
      }
      

      初始化Service

      protected void initInternal() throws LifecycleException {
          //调用父类初始化(设置名称:Tomcat,类型:Server)
          super.initInternal();
          //2.2.1.1.1.1 初始化engine
          if (engine != null) {
              engine.init();
          }
          // Initialize any Executors
          //2.2.1.1.1.2 初始化executor
          for (Executor executor : findExecutors()) {
              if (executor instanceof JmxEnabled) {
                  ((JmxEnabled) executor).setDomain(getDomain());
              }
              executor.init();
          }
          // Initialize mapper listener
          //2.2.1.1.1.3 初始化mapperListener
          mapperListener.init();
          // Initialize our defined Connectors
          //2.2.1.1.1.4 初始化connector
          synchronized (connectorsLock) {
              for (Connector connector : connectors) {
                  connector.init();
              }
          }
      }
      

      初始化engine

      protected void initInternal() throws LifecycleException {
          // Ensure that a Realm is present before any attempt is made to start
          // one. This will create the default NullRealm if necessary.
          // 在尝试启动一个Realm之前,请确保存在一个Realm。如有必要,这将创建默认的NullRealm
          getRealm();
          super.initInternal();
      }
      public Realm getRealm() {
          Realm configured = super.getRealm();
          // If no set realm has been called - default to NullRealm
          // This can be overridden at engine, context and host level
          if (configured == null) {
              configured = new NullRealm();
              this.setRealm(configured);
          }
          return configured;
      }
      

      初始化executor

      它还是调的父类 LifecycleMBeanBase 的方法

      protected void initInternal() throws LifecycleException {
          super.initInternal();
      }
      

      初始化mapperListener

      protected void initInternal() throws LifecycleException {
          // If oname is not null then registration has already happened via preRegister().
          // 如果oname不为null,则已经通过preRegister()进行了注册
          if (oname == null) {
              mserver = Registry.getRegistry(null, null).getMBeanServer();
              oname = register(this, getObjectNameKeyProperties());
          }
      }
      

      初始化connector

      protected void initInternal() throws LifecycleException {
          super.initInternal();
          if (protocolHandler == null) {
              throw new LifecycleException(
                      sm.getString("coyoteConnector.protocolHandlerInstantiationFailed"));
          }
          // Initialize adapter
          adapter = new CoyoteAdapter(this);
          protocolHandler.setAdapter(adapter);
          if (service != null) {
              protocolHandler.setUtilityExecutor(service.getServer().getUtilityExecutor());
          }
          // Make sure parseBodyMethodsSet has a default
          if (null == parseBodyMethodsSet) {
              setParseBodyMethods(getParseBodyMethods());
          }
          if (protocolHandler.isAprRequired() &amp;&amp; !AprStatus.isInstanceCreated()) {
              throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprListener",
                      getProtocolHandlerClassName()));
          }
          if (protocolHandler.isAprRequired() &amp;&amp; !AprStatus.isAprAvailable()) {
              throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprLibrary",
                      getProtocolHandlerClassName()));
          }
          if (AprStatus.isAprAvailable() &amp;&amp; AprStatus.getUseOpenSSL() &amp;&amp;
                  protocolHandler instanceof AbstractHttp11JsseProtocol) {
              AbstractHttp11JsseProtocol&lt;?&gt; jsseProtocolHandler =
                      (AbstractHttp11JsseProtocol&lt;?&gt;) protocolHandler;
              if (jsseProtocolHandler.isSSLEnabled() &amp;&amp;
                      jsseProtocolHandler.getSslImplementationName() == null) {
                  // OpenSSL is compatible with the JSSE configuration, so use it if APR is available
                  jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
              }
          }
          try {
              //2.2.1.1.1.5 初始化protocolHandler
              protocolHandler.init();
          } catch (Exception e) {
              throw new LifecycleException(
                      sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
          }
      }
      

      初始化protocolHandler

      public void init() throws Exception {
          // Upgrade protocols have to be configured first since the endpoint
          // init (triggered via super.init() below) uses this list to configure
          // the list of ALPN protocols to advertise
          // 必须先配置升级协议,因为端点初始化(通过下面的super.init()触发)使用此列表来配置要发布的ALPN协议列表
          for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {
              configureUpgradeProtocol(upgradeProtocol);
          }
          super.init();
      }
      

      Debug发现这个 upgradeProtocols 为空,直接走下面父类(AbstractProtocol)的 init 方法:

      public void init() throws Exception {
          if (getLog().isInfoEnabled()) {
              getLog().info(sm.getString("abstractProtocolHandler.init", getName()));
              logPortOffset();
          }
          if (oname == null) {
              // Component not pre-registered so register it
              oname = createObjectName();
              if (oname != null) {
                  Registry.getRegistry(null, null).registerComponent(this, oname, null);
              }
          }
          if (this.domain != null) {
              rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
              Registry.getRegistry(null, null).registerComponent(
                      getHandler().getGlobal(), rgOname, null);
          }
          String endpointName = getName();
          endpoint.setName(endpointName.substring(1, endpointName.length()-1));
          endpoint.setDomain(domain);
          //2.2.1.1.1.6 初始化endpoint
          endpoint.init();
      }
      

      上面又是一堆初始化,这个咱暂且不关注,注意最底下有一个 endpoint.init :

      初始化endpoint

      来到 AbstractEndPoint :

      public final void init() throws Exception {
          // Debug为false
          if (bindOnInit) {
              bindWithCleanup();
              bindState = BindState.BOUND_ON_INIT;
          }
          if (this.domain != null) {
              // Register endpoint (as ThreadPool - historical name)
              oname = new ObjectName(domain + ":type=ThreadPool,name="" + getName() + """);
              Registry.getRegistry(null, null).registerComponent(this, oname, null);
              ObjectName socketPropertiesOname = new ObjectName(domain +
                      ":type=ThreadPool,name="" + getName() + "",subType=SocketProperties");
              socketProperties.setObjectName(socketPropertiesOname);
              Registry.getRegistry(null, null).registerComponent(socketProperties, socketPropertiesOname, null);
              for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
                  registerJmx(sslHostConfig);
              }
          }
      }
      

      这里面又是初始化 oname ,又是配置 socketProperties 的,但这里面再也没见到 init 方法,证明这部分初始化过程已经结束了。

       初始化小结

      嵌入式 Tomcat 的组件初始化步骤顺序如下:

      • Server
      • Service
      • Engine
      • Executor
      • MapperListener
      • Connector
      • Protocol
      • EndPoint

      startInternal:启动Internal

      startInternal 方法中有两部分启动:globalNamingResources 启动,services 启动。分别来看:

      protected void startInternal() throws LifecycleException {
          // 发布启动事件
          fireLifecycleEvent(CONFIGURE_START_EVENT, null);
          setState(LifecycleState.STARTING);
          // 2.2.1.2.1 NamingResources启动
          globalNamingResources.start();
          // Start our defined Services
          synchronized (servicesLock) {
              for (int i = 0; i &lt; services.length; i++) {
                  // 2.2.1.2.2 Service启动
                  services[i].start();
              }
          }
          if (periodicEventDelay &gt; 0) {
              monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
                      new Runnable() {
                          @Override
                          public void run() {
                              startPeriodicLifecycleEvent();
                          }
                      }, 0, 60, TimeUnit.SECONDS);
          }
      }
      

      NamingResources启动

      只是发布事件和设置状态而已

      protected void startInternal() throws LifecycleException {
          fireLifecycleEvent(CONFIGURE_START_EVENT, null);
          setState(LifecycleState.STARTING);
      }
      

      Service启动

      依次启动 Engine 、Executor 、MapperListener 、Connector 

      protected void startInternal() throws LifecycleException {
          if(log.isInfoEnabled())
              log.info(sm.getString("standardService.start.name", this.name));
          setState(LifecycleState.STARTING);
          // Start our defined Container first
          if (engine != null) {
              synchronized (engine) {
                  // 2.2.1.2.2.1 启动Engine
                  engine.start();
              }
          }
          synchronized (executors) {
              for (Executor executor: executors) {
                  // 2.2.1.2.2.3 启动Executor
                  executor.start();
              }
          }
          // 2.2.1.2.2.4 启动MapperListener
          mapperListener.start();
          // Start our defined Connectors second
          synchronized (connectorsLock) {
              for (Connector connector: connectors) {
                  // If it has already failed, don't try and start it
                  if (connector.getState() != LifecycleState.FAILED) {
                      // 2.2.1.2.2.5 启动connector
                      connector.start();
                  }
              }
          }
      }
      

      启动Engine

      protected synchronized void startInternal() throws LifecycleException {
          // Log our server identification information
          if (log.isInfoEnabled()) {
              log.info(sm.getString("standardEngine.start", ServerInfo.getServerInfo()));
          }
          // Standard container startup
          super.startInternal();
      }
      

      它直接调的父类 ContainerBase 的 startInternal 方法:

      protected synchronized void startInternal() throws LifecycleException {
          // Start our subordinate components, if any
          logger = null;
          getLogger();
          // Cluster与集群相关,SpringBoot项目中使用嵌入式Tomcat,不存在集群
          Cluster cluster = getClusterInternal();
          if (cluster instanceof Lifecycle) {
              ((Lifecycle) cluster).start();
          }
          // Realm与授权相关
          Realm realm = getRealmInternal();
          if (realm instanceof Lifecycle) {
              ((Lifecycle) realm).start();
          }
          // Start our child containers, if any
          // Container的类型是StandardHost
          Container children[] = findChildren();
          List&lt;Future&lt;Void&gt;&gt; results = new ArrayList&lt;&gt;();
          for (int i = 0; i &lt; children.length; i++) {
              //异步初始化Host
              results.add(startStopExecutor.submit(new StartChild(children[i])));
          }
          MultiThrowable multiThrowable = null;
          for (Future&lt;Void&gt; result : results) {
              try {
                  result.get();
              } catch (Throwable e) {
                  log.error(sm.getString("containerBase.threadedStartFailed"), e);
                  if (multiThrowable == null) {
                      multiThrowable = new MultiThrowable();
                  }
                  multiThrowable.add(e);
              }
          }
          if (multiThrowable != null) {
              throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
                      multiThrowable.getThrowable());
          }
          // Start the Valves in our pipeline (including the basic), if any
          if (pipeline instanceof Lifecycle) {
              ((Lifecycle) pipeline).start();
          }
          setState(LifecycleState.STARTING);
          // Start our thread
          if (backgroundProcessorDelay &gt; 0) {
              monitorFuture = Container.getService(ContainerBase.this).getServer()
                      .getUtilityExecutor().scheduleWithFixedDelay(
                              new ContainerBackgroundProcessorMonitor(), 0, 60, TimeUnit.SECONDS);
          }
      }
      

      StartChild 实现了带返回值的异步多线程接口 Callable 核心方法就是在 call

      private static class StartChild implements Callable<Void>
      

      它实现了带返回值的异步多线程接口 Callable !那里面的核心方法就是 call :

      public Void call() throws LifecycleException {
          child.start();
          return null;
      }
      

      它在这里初始化 child,而通过Debug得知 child 的类型是 StandardHost,故来到 StandardHost 的 start 方法:

      protected synchronized void startInternal() throws LifecycleException {
          // Set error report valve
          String errorValve = getErrorReportValveClass();
          if ((errorValve != null) &amp;&amp; (!errorValve.equals(""))) {
              try {
                  boolean found = false;
                  Valve[] valves = getPipeline().getValves();
                  for (Valve valve : valves) {
                      if (errorValve.equals(valve.getClass().getName())) {
                          found = true;
                          break;
                      }
                  }
                  if(!found) {
                      Valve valve =
                          (Valve) Class.forName(errorValve).getConstructor().newInstance();
                      getPipeline().addValve(valve);
                  }
              } catch (Throwable t) {
                  ExceptionUtils.handleThrowable(t);
                  log.error(sm.getString(
                          "standardHost.invalidErrorReportValveClass",
                          errorValve), t);
              }
          }
          super.startInternal();
      }
      

      上面的一个大if结构是设置错误提示页面的,下面又调父类的 startInternal :

      protected synchronized void startInternal() throws LifecycleException {
          // ......
          // Start our child containers, if any
          Container children[] = findChildren();
          List<Future<Void>> results = new ArrayList<>();
          for (int i = 0; i < children.length; i++) {
              results.add(startStopExecutor.submit(new StartChild(children[i])));
          }
      

      又回来了。。。因为一个 Host 包含一个 Context 。

      Host 搜索children就会搜到它下面的 Context ,之后又是下面的初始化过程,进入 Context 的初始化:

       启动TomcatEmbeddedContext

      在TomcatEmbeddedContext有如下组件被调用了 start 方法:

      • StandardRoot
      • DirResourceSet
      • WebappLoader
      • JarResourceSet
      • StandardWrapper
      • StandardPineline
      • StandardWrapperValve
      • NonLoginAuthenticator
      • StandardContextValve
      • StandardManager
      • LazySessionIdGenerator

      启动Executor

      但由于 Executor 没有实现 startInternal 方法,所以不会启动

          synchronized (executors) {
              for (Executor executor: executors) {
                  executor.start();
              }
          }
      

      启动MapperListener

      接下来启动 MapperListener :

      public void startInternal() throws LifecycleException {
          setState(LifecycleState.STARTING);
          Engine engine = service.getContainer();
          if (engine == null) {
              return;
          }
          // 获取当前部署的主机名(本地调试为localhost)
          findDefaultHost();
          // 把当前自身注册到Engine、Host、Context、Wrapper中
          addListeners(engine);
          // 取出的Container的类型为Host
          Container[] conHosts = engine.findChildren();
          for (Container conHost : conHosts) {
              Host host = (Host) conHost;
              if (!LifecycleState.NEW.equals(host.getState())) {
                  // Registering the host will register the context and wrappers
                  //将Host、Context、Wrapper注册到当前监听器中
                  registerHost(host);
              }
          }
      }
      

       启动Connector

      最后一步是启动 Connector 。

          // Start our defined Connectors second
          synchronized (connectorsLock) {
              for (Connector connector: connectors) {
                  // If it has already failed, don't try and start it
                  if (connector.getState() != LifecycleState.FAILED) {
                      connector.start();
                  }
              }
          }
      

       启动总结

      启动过程依次启动了如下组件:

      • NamingResources
      • Service
      • Engine
      • Host
      • Context
      • Wrapper
      • Executor
      • MapperListener

      三、注册Bean生命周期

      3.1 WebServerStartStopLifecycle(Web服务器启动-停止生命周期)

      WebServerStartStopLifecycle实现了Lifecycle,在容器刷新完成时会调用finishRefresh()

      @Override
      public void start() {
         //启动Tomcat 容器
         this.webServer.start();
         this.running = true;
         this.applicationContext
               .publishEvent(new ServletWebServerInitializedEvent(this.webServer, this.applicationContext));
      }
      
      public void start() throws WebServerException {
          synchronized (this.monitor) {
              if (this.started) {
                  return;
              }
              try {
                  // 3.1.1 还原、启动Connector
                  addPreviouslyRemovedConnectors();
                  // 只拿一个Connector
                  Connector connector = this.tomcat.getConnector();
                  if (connector != null &amp;&amp; this.autoStart) {
                      // 3.1.2 延迟启动
                      performDeferredLoadOnStartup();
                  }
                  // 检查Connector是否正常启动
                  checkThatConnectorsHaveStarted();
                  this.started = true;
                  logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
                          + getContextPath() + "'");
              }
              // catch ......
              finally {
                  // 解除ClassLoader与TomcatEmbeddedContext的绑定关系
                  Context context = findContext();
                  ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
              }
          }
      }
      

      3.1.1 addPreviouslyRemovedConnectors:启动Connector

      private void addPreviouslyRemovedConnectors() {
          Service[] services = this.tomcat.getServer().findServices();
          for (Service service : services) {
              Connector[] connectors = this.serviceConnectors.get(service);
              if (connectors != null) {
                  for (Connector connector : connectors) {
                      // 添加并启动
                      service.addConnector(connector);
                      if (!this.autoStart) {
                          stopProtocolHandler(connector);
                      }
                  }
                  this.serviceConnectors.remove(service);
              }
          }
      }
      

      可以发现它将一个缓存区的 Connector 一个一个取出放入 Service 中。注意在 service.addConnector 中有顺便启动的部分:

      public void addConnector(Connector connector) {
          synchronized (connectorsLock) {
              connector.setService(this);
              Connector results[] = new Connector[connectors.length + 1];
              System.arraycopy(connectors, 0, results, 0, connectors.length);
              results[connectors.length] = connector;
              connectors = results;
          }
          try {
              if (getState().isAvailable()) {
                  // 启动Connector
                  connector.start();
              }
          } catch (LifecycleException e) {
              throw new IllegalArgumentException(
                      sm.getString("standardService.connector.startFailed", connector), e);
          }
          // Report this property change to interested listeners
          support.firePropertyChange("connector", null, connector);
      }
      

      前面的部分是取出 Connector ,并与 Service 绑定,之后中间部分的try块,会启动 Connector :

      protected void startInternal() throws LifecycleException {
          // Validate settings before starting
          if (getPortWithOffset() &lt; 0) {
              throw new LifecycleException(sm.getString(
                      "coyoteConnector.invalidPort", Integer.valueOf(getPortWithOffset())));
          }
          setState(LifecycleState.STARTING);
          try {
              // 启动ProtocolHandler
              protocolHandler.start();
          } catch (Exception e) {
              throw new LifecycleException(
                      sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
          }
      }
      

      Connector 的启动会引发 ProtocolHandler 的启动:

      public void start() throws Exception {
          if (getLog().isInfoEnabled()) {
              getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
              logPortOffset();
          }
          // 启动EndPoint
          endpoint.start();
          monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
                  new Runnable() {
                      @Override
                      public void run() {
                          if (!isPaused()) {
                              startAsyncTimeout();
                          }
                      }
                  }, 0, 60, TimeUnit.SECONDS);
      }
      

      ProtocolHandler 的启动会引发 EndPoint 的启动,至此所有组件均已启动完毕。

       performDeferredLoadOnStartup:延迟启动

      这里面会延迟启动 TomcatEmbeddedContext

      private void performDeferredLoadOnStartup() {
          try {
              for (Container child : this.tomcat.getHost().findChildren()) {
                  if (child instanceof TomcatEmbeddedContext) {
                      // 延迟启动Context
                      ((TomcatEmbeddedContext) child).deferredLoadOnStartup();
                  }
              }
          }
          catch (Exception ex) {
              if (ex instanceof WebServerException) {
                  throw (WebServerException) ex;
              }
              throw new WebServerException("Unable to start embedded Tomcat connectors", ex);
          }
      }
      

      四、初始化上下文环境

      这里在Spring中已经刷新过一次,详情:在文章 https://www.jb51.net/article/277946.htm 的 prepareRefresh:初始化前的预处理中

      以上就是ServletWebServerApplicationContext创建Web容器Tomcat示例的详细内容,更多关于Web容器Tomcat创建的资料请关注3672js教程其它相关文章!

      您可能感兴趣的文章:
      • tomcat的webapps目录下的应用删除部署详解
      • 删除 Tomcat webapps 目录自带项目方式详解
      • 使用IDEA创建servlet JavaWeb 应用及使用Tomcat本地部署的实现
      • Eclipse开发JavaWeb项目配置Tomcat的方法步骤
      • Tomcat打破双亲委派机制实现隔离Web应用的方法
      相关栏目:

      相关文章

        用户点评