ServletWebServerApplicationContext创建Web容器Tomcat示例

作者:无名之辈J 时间:2023-10-12 12:28:33 

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:初始化前的预处理中

来源:https://juejin.cn/post/7208384641190674492

标签:ServletWebServerApplicationContext,Web,Tomcat,容器创建
0
投稿

猜你喜欢

  • C#.Net ArrayList的使用方法

    2022-01-17 05:29:14
  • Android string.xml中的替换方法

    2021-11-10 11:47:56
  • 解析Java实现随机验证码功能的方法详解

    2022-09-25 23:26:14
  • C++实现LeetCode(2.两个数字相加)

    2023-06-23 16:51:11
  • Android studio实现简单的计算器

    2022-09-07 23:23:28
  • JavaWeb开发之【Tomcat 环境配置】MyEclipse+IDEA配置教程

    2022-05-04 12:50:18
  • Android自定义短信验证码组件

    2022-10-06 00:30:13
  • winform实现可拖动的自定义Label控件

    2022-12-14 09:11:36
  • C#实现HSL颜色值转换为RGB的方法

    2022-02-21 09:56:11
  • C#实现提取Word中插入的多媒体文件(视频,音频)

    2022-09-06 14:45:20
  • IDEA创建Java项目文件并运行教程解析

    2023-01-14 15:50:47
  • Spring Boot中的那些条件判断的实现方法

    2023-04-26 15:02:07
  • Android实现创建或升级数据库时执行语句

    2022-07-10 11:58:58
  • java精度计算代码 java指定精确小数位

    2023-07-31 03:03:58
  • Android 开发随手笔记之使用摄像头拍照

    2023-01-31 05:17:22
  • Java Switch对各类型支持实现原理

    2023-10-28 04:45:37
  • 如何通过SpringBoot实现商城秒杀系统

    2023-11-24 23:02:33
  • 详解Java如何实现小顶堆和大顶堆

    2023-11-10 04:03:05
  • Hibernate中load方法与get方法的区别

    2021-07-18 09:32:16
  • java字符串的重要使用方法以及实例

    2023-11-13 23:11:51
  • asp之家 软件编程 m.aspxhome.com