iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >ServletWebServerApplicationContext如何创建Web容器Tomcat
  • 207
分享到

ServletWebServerApplicationContext如何创建Web容器Tomcat

2023-07-05 12:07:14 207人浏览 八月长安
摘要

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

今天小编给大家分享一下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 的组件初始化步骤顺序如下:

    • 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()

    @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”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

    --结束END--

    本文标题: ServletWebServerApplicationContext如何创建Web容器Tomcat

    本文链接: https://www.lsjlt.com/news/351620.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • ServletWebServerApplicationContext如何创建Web容器Tomcat
      今天小编给大家分享一下ServletWebServerApplicationContext如何创建Web容器Tomcat的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇...
      99+
      2023-07-05
    • 如何创建Docker容器
      本篇内容介绍了“如何创建Docker容器”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!GIScript2016是支持Python3的地理空间...
      99+
      2023-06-19
    • 如何创建VS2003 Web Service
      今天小编给大家分享一下如何创建VS2003 Web Service的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。用VS.Ne...
      99+
      2023-06-17
    • 容器云如何搭建web服务器
      要搭建一个容器云中的Web服务器,可以按照以下步骤进行操作:1. 选择一个容器管理平台:选择一个合适的容器管理平台,如Docker、...
      99+
      2023-09-22
      容器云 web服务器 服务器
    • SpringBoot 创建web项目并部署到外部Tomcat
      前言使用SpringBoot来开发项目相对于传统模式,要快速优雅许多,相信目前国内绝大部分web项目的开发还没有使用SpringBoot来做,如果你正需要开发一个web项目,不妨尝试使用SpringBoot来做。本身SpringBoot是内...
      99+
      2023-05-31
      spring boot web
    • JavaWeb 入门篇:创建Web项目,Idea配置tomcat
      目录创建一个maven项目项目结构添加框架在pom.xml中添加如下依赖配置tomcat添加完如下图:解决导入包问题:启动测试:总结创建一个maven项目 项目结构 添加框架...
      99+
      2024-04-02
    • 创建的docker容器如何关闭
      这篇文章主要为大家展示了“创建的docker容器如何关闭”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“创建的docker容器如何关闭”这篇文章吧。以在Linux机器上为例,启动一个新的容器,可以...
      99+
      2023-06-03
    • Docker如何使用run创建容器
      这篇文章主要为大家展示了“Docker如何使用run创建容器”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Docker如何使用run创建容器”这篇文章吧。使用r...
      99+
      2024-04-02
    • springboot如何关掉tomcat容器
      目录springboot关掉tomcat容器springboot使用第三方tomcat1.改pom2.再加一个启动类3.打war包springboot关掉tomcat容器 有的时候需...
      99+
      2024-04-02
    • J2EE如何创建web客户端
      本篇内容主要讲解“J2EE如何创建web客户端”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“J2EE如何创建web客户端”吧!web客户端包含在examples/src/EJB/converte...
      99+
      2023-06-03
    • eclipse中如何创建第一个tomcat项目
      要在Eclipse中创建第一个Tomcat项目,请按照以下步骤操作:1. 打开Eclipse并选择“File”菜单,然后选择“New...
      99+
      2023-09-27
      eclipse tomcat
    • Docker如何创建并进入mysql容器
      这篇文章主要介绍“Docker如何创建并进入mysql容器”,在日常操作中,相信很多人在Docker如何创建并进入mysql容器问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Docker如何创建并进入mysq...
      99+
      2023-07-05
    • tomcat中怎么搭建web服务器
      在Tomcat中搭建web服务器可以通过以下步骤实现: 下载并安装Tomcat:首先需要下载Tomcat的安装包,并解压到本地目...
      99+
      2024-04-09
      tomcat 服务器
    • tomcat启动报创建bean错误如何解决
      当Tomcat启动报创建Bean错误时,可能是由于以下几种原因导致的:1. 类路径问题:检查类路径中是否缺少了必要的依赖库。可以通过...
      99+
      2023-09-11
      tomcat
    • IDEA2023.1.3创建Java Web项目并配置Tomcat(傻瓜式教程)
      本篇教程只针对IDEA2023.1.3版的Java Web项目创建以及配置Tomcat,不包含Tomcat下载教程 选择New Project,设置好项目名和JDK,点击Create  2.打开Project Structure 在Mo...
      99+
      2023-08-31
      java 开发语言 tomcat idea java-ee servlet intellij-idea
    • Docker如何创建运行多个mysql容器
      这篇文章主要介绍“Docker如何创建运行多个mysql容器”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Docker如何创建运行多个mysql容器”文章能帮助大家...
      99+
      2024-04-02
    • docker容器中如何创建多个镜像
      要在Docker容器中创建多个镜像,您可以执行以下步骤: 在Docker容器中启动一个新的容器,并使用该容器作为构建环境。 在构建...
      99+
      2024-04-02
    • IDEA2022创建Web项目配置Tomcat的详细图文说明
      下面是在idea上面配置一个Tomcat的项目环境。 1.首先创建普通的一个Java项目,不要选择JavaEE  2.创建完成后按照下图所示,依次选择 File ->...
      99+
      2023-05-14
      idea新建web项目并配置tomcat ideatomcat配置web项目 IDEA配置tomcat
    • HTML如何创建一个Web Worker文件
      这篇文章主要为大家展示了“HTML如何创建一个Web Worker文件”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“HTML如何创建一个Web Worker文件...
      99+
      2024-04-02
    • Intellij IDEA怎么创建Web项目并在Tomcat中部署运行
      这篇文章主要介绍“Intellij IDEA怎么创建Web项目并在Tomcat中部署运行”,在日常操作中,相信很多人在Intellij IDEA怎么创建Web项目并在Tomcat中部署运行问题上存在疑惑,小编查阅了各式资料,整理出简单好用的...
      99+
      2023-06-04
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作