文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

ServletWebServerApplicationContext如何创建Web容器Tomcat

2023-07-05 12:18

关注

今天小编给大家分享一下ServletWebServerApplicationContext如何创建Web容器Tomcat的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

正文

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

@Overrideprotected 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;   }      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工厂

@Configurationclass 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.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 的组件初始化步骤顺序如下:

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 方法:

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

 启动总结

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

三、注册Bean生命周期

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

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

@Overridepublic 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);    }}

以上就是“ServletWebServerApplicationContext如何创建Web容器Tomcat”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯