美文网首页
3 嵌入式web容器

3 嵌入式web容器

作者: zacone | 来源:发表于2019-01-09 22:32 被阅读0次

    种类

    spring-boot支持使用jetty、netty、tomcat、undertow作为嵌入式web容器

    获取web容器实例

            public void refresh() throws BeansException, IllegalStateException {
            synchronized(this.startupShutdownMonitor) {
                this.prepareRefresh();
                ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
                this.prepareBeanFactory(beanFactory);
    
                try {
                    this.postProcessBeanFactory(beanFactory);
                    this.invokeBeanFactoryPostProcessors(beanFactory);
                    this.registerBeanPostProcessors(beanFactory);
                    this.initMessageSource();
                    this.initApplicationEventMulticaster();
                    this.onRefresh();
                    this.registerListeners();
                    this.finishBeanFactoryInitialization(beanFactory);
                    this.finishRefresh();
                } catch (BeansException var9) {
                    if (this.logger.isWarnEnabled()) {
                        this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                    }
    
                    this.destroyBeans();
                    this.cancelRefresh(var9);
                    throw var9;
                } finally {
                    this.resetCommonCaches();
                }
    
            }
        }
    
        protected void onRefresh() throws BeansException {
        }
    
        protected void finishRefresh() {
            this.clearResourceCaches();
            this.initLifecycleProcessor();
            this.getLifecycleProcessor().onRefresh();
            this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
            LiveBeansView.registerApplicationContext(this);
        }
    

    spring-framework初始化的步骤如上,而spring-boot的嵌入式web容器实例化在onRefresh方法里进行。
    spring-boot支持两种容器方案,一种为阻塞式的servlet,另一种为非阻塞的reactive,spring-boot在启动时会根据classpath下文件推断当前使用的是何种容器方案,从而使用ReactiveWebServerApplicationContextServletWebServerApplicationContext类实例,它们都继承了spring-framework的GenericWebApplicationContext类,并重写了onRefresh方法。

    servlet方案容器的实例化

    ServletWebServerApplicationContext.java

        @Override
        protected void onRefresh() {
            super.onRefresh();
            try {
                createWebServer();
            }
            catch (Throwable ex) {
                throw new ApplicationContextException("Unable to start web server", ex);
            }
        }
    
            private void createWebServer() {
            WebServer webServer = this.webServer;
            ServletContext servletContext = getServletContext();
            if (webServer == null && servletContext == null) {
                ServletWebServerFactory factory = getWebServerFactory();
                this.webServer = factory.getWebServer(getSelfInitializer());
            }
            else if (servletContext != null) {
                try {
                    getSelfInitializer().onStartup(servletContext);
                }
                catch (ServletException ex) {
                    throw new ApplicationContextException("Cannot initialize servlet context",
                            ex);
                }
            }
            initPropertySources();
        }
    
            protected ServletWebServerFactory getWebServerFactory() {
            // Use bean names so that we don't consider the hierarchy
            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));
            }
            return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
        }
    

    容器类型存在成员变量webServer中,在实例化容器前,会先判断webServer是否已经被实例化,webServer是一个接口,所有的嵌入式容器启动类都实现了这个接口。
    getWebServerFactory方法会从beanFactory中获取实现了ServletWebServerFactory接口的类实例,通过其getWebServer方法可以实例化具体的web容器实例并放入实现了WebServer的类中返回。
    上一段提到需要从beanFactory中获取实现了ServletWebServerFactory接口的类实例,这个类实例来自于spring-boot提供的auto-configuration功能,专用的嵌入式容器jar包会自动配置ServletWebServerFactory的实现。

    servlet方案容器的运行

            @Override
        protected void finishRefresh() {
            super.finishRefresh();
            WebServer webServer = startWebServer();
            if (webServer != null) {
                publishEvent(new ServletWebServerInitializedEvent(webServer, this));
            }
        }
    
            private WebServer startWebServer() {
            WebServer webServer = this.webServer;
            if (webServer != null) {
                webServer.start();
            }
            return webServer;
        }
    

    上文说到容器的实例化在onRefresh方法进行,而容器的启动则是在finishRefresh方法进行,同样的,ServletWebServerApplicationContext类重写了GenericWebApplicationContext类的finishRefresh方法。
    该方法直接调用了webServerstart方法启动容器。就这样,项目容器的WebServer接口实现类便会被启动,具体的启动方法因容器而异,具体启动的实现可参考NettyWebServerTomcatWebServerJettyWebServerUndertowWebServerUndertowServletWebServer,spring-boot提供了这几种嵌入式容器启动的实现。

    reactive方案容器的实例化

            @Override
        protected void onRefresh() {
            super.onRefresh();
            try {
                createWebServer();
            }
            catch (Throwable ex) {
                throw new ApplicationContextException("Unable to start reactive web server",
                        ex);
            }
        }
    
           private void createWebServer() {
            ServerManager serverManager = this.serverManager;
            if (serverManager == null) {
                this.serverManager = ServerManager.get(getWebServerFactory());
            }
            initPropertySources();
        }
    
            protected ReactiveWebServerFactory getWebServerFactory() {
            // Use bean names so that we don't consider the hierarchy
            String[] beanNames = getBeanFactory()
                    .getBeanNamesForType(ReactiveWebServerFactory.class);
            if (beanNames.length == 0) {
                throw new ApplicationContextException(
                        "Unable to start ReactiveWebApplicationContext due to missing "
                                + "ReactiveWebServerFactory bean.");
            }
            if (beanNames.length > 1) {
                throw new ApplicationContextException(
                        "Unable to start ReactiveWebApplicationContext due to multiple "
                                + "ReactiveWebServerFactory beans : "
                                + StringUtils.arrayToCommaDelimitedString(beanNames));
            }
            return getBeanFactory().getBean(beanNames[0], ReactiveWebServerFactory.class);
        }
    

    与servlet方案的容器实例化类似,reactive方案的容器实例化仅仅将获取容器实例的接口从ServletWebServerFactory变成了ReactiveWebServerFactory,嵌入式容器jar包会提供实现了ServletWebServerFactory接口的bean。

    reactive方案容器的运行

            @Override
        protected void finishRefresh() {
            super.finishRefresh();
            WebServer webServer = startReactiveWebServer();
            if (webServer != null) {
                publishEvent(new ReactiveWebServerInitializedEvent(webServer, this));
            }
        }
    
            private WebServer startReactiveWebServer() {
            ServerManager serverManager = this.serverManager;
            ServerManager.start(serverManager, this::getHttpHandler);
            return ServerManager.getWebServer(serverManager);
        }
    
            public static void start(ServerManager manager,
                    Supplier<HttpHandler> handlerSupplier) {
                if (manager != null && manager.server != null) {
                    manager.handler = handlerSupplier.get();
                    manager.server.start();
                }
            }
    

    与servlet方案容器的实现一致,直接调用start方法运行即可。

    相关文章

      网友评论

          本文标题:3 嵌入式web容器

          本文链接:https://www.haomeiwen.com/subject/upgirqtx.html