zoukankan      html  css  js  c++  java
  • 嵌入式web容器

    种类

    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);
        }
    ServletWebServerApplicationContext.java
      容器类型存在成员变量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方法运行即可。



    博客园:https://www.cnblogs.com/xianquan
    Copyright ©2020 l-coil
    【转载文章务必保留出处和署名,谢谢!】
查看全文
  • 相关阅读:
    面试题3(百思教育面试软件开发岗位笔试题)
    python开发工具安装
    涉及 委托事件 程序运行越来越慢
    整理收藏
    数据库作业创建
    剑指offer-面试题37:序列化二叉树及二叉树的基本操作和测试
    剑指offer-面试题41:数据流中的中位数
    快速排序及其优化
    冒泡排序算法及相应的优化
    leetcode问题:缺失数字
  • 原文地址:https://www.cnblogs.com/xianquan/p/13018813.html
  • Copyright © 2011-2022 走看看