中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

ServletWebServerApplicationContext如何創建Web容器Tomcat

發布時間:2023-03-14 15:43:15 來源:億速云 閱讀:157 作者:iii 欄目:開發技術

今天小編給大家分享一下ServletWebServerApplicationContext如何創建Web容器Tomcat的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    正文

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

    以上就是“ServletWebServerApplicationContext如何創建Web容器Tomcat”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    商洛市| 宽甸| 綦江县| 江源县| 博罗县| 泽普县| 桃园市| 稷山县| 营口市| 吉木萨尔县| 河北省| 合水县| 治县。| 图们市| 青河县| 尉氏县| 犍为县| 靖宇县| 贵溪市| 类乌齐县| 镇赉县| 平远县| 阿克陶县| 宣城市| 高唐县| 陆川县| 湄潭县| 马关县| 固原市| 永登县| 黔西县| 泸溪县| 新建县| 竹北市| 隆德县| 田东县| 句容市| 三河市| 金阳县| 栾川县| 康马县|