• Spring Boot源码阅读如何启动内置web容器(三)


    说明

    在Spring Boot-源码阅读-启动主流程(一) <8-13>触发 容器初始化是AnnotationConfigServletWebServerApplicationContext

    类图

    <1>

    <8-16>处触发容器的refresh

      /**
         * 优雅关闭 
         * @param context
         */
        static final SpringApplicationShutdownHook shutdownHook = new SpringApplicationShutdownHook();
        private void refreshContext(ConfigurableApplicationContext context) {
            if (this.registerShutdownHook) {
                shutdownHook.registerApplicationContext(context);
            }
            //<2>调用容器的refresh方法进入spring生命周期
            refresh(context);
        }

    <2>

    更多spring生命周期代码可以参考:https://www.cnblogs.com/LQBlog/p/13954302.html

    org.springframework.context.support.AbstractApplicationContext#refresh

    @Override
        public void refresh() throws BeansException, IllegalStateException {
            /*
             *加锁 防止在初始化过程中,继续调用初始化和 销毁的方法
             */
            synchronized (this.startupShutdownMonitor) {
    
                //初始化容器的准备工作
                // 将 active 属性设置为 true,closed 属性设置为 false,它们都是 AtomicBoolean 类型
                prepareRefresh();
    
                //将会初始化 BeanFactory、加载 Bean、注册 Bean 等等。只是将需要初始化的bean通过BeanDefinition封装
                //BeanDefinition封装了如何初始化bean
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                //为beanFactory设置创建bean的ClassLoader 添加几个 BeanPostProcessor,手动注册几个特殊的 bean 供后续使用
                prepareBeanFactory(beanFactory);
    
                try {
                    /**
                     *这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
                     *通过beanFactory我们可以获取并改变BeanDefinition 的属性改变将要创建bean的信息
                     * 钩子方法 目前空实现               */
                    postProcessBeanFactory(beanFactory);
    
    
    
                    /**
                     * 实例化并调用所有已注册的 BeanFactoryPostProcessor的实现类
                     * 这里是spring提供的扩展展点。我们可以通过实现BeanFactoryPostProcessor 在回调拿到beanFactory
                     * 我们可以往里面注册BeanDefinition或者改变Definition的值
                     * 如何注册一个BeanDefinition:
                     *可以参考:org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition使用
                     *BeanDefinitionReaderUtils#registerBeanDefinition 注册 使用例子可参考:附录                 *典型例子可以参考Import原理
                     * */
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    /**
                     * 初始化 BeanPostProcessor的实现类 注意这里并没有调用 只是先初始化这个接口的实现类到容器
                     * 1.实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
                     * 2.实例化、依赖注入、初始化完毕时执行
                     */
                    registerBeanPostProcessors(beanFactory);
    
                    //初始化当前 ApplicationContext 的 MessageSource 国际化相关
                    initMessageSource();
    
    
                    /**
                     * 初始化当前 ApplicationContext 的事件广播器 先在容器中找 如果没有则创建默认的
                     * ApplicationEventMulticaster 这个接口可以管理很多个ApplicationListener对象。并将事件发布给这些监听器                 * 可参考附录用法
                     */
                    initApplicationEventMulticaster();
    
                     //<3>被子类重写了
                    onRefresh();
    
                    // 注册事件监听器,监听器需要实现 ApplicationListener 接口 
                    registerListeners();
    
                    /**
                     * 核心方法
                     * 初始化所有的 singleton bean BeanDefinition isLazyInit为 lazy-init 的除外
                     */
                    finishBeanFactoryInitialization(beanFactory);
    
                    /**
                     * 完成刷新Context,主要调用org.springframework.context.LifecycleProcessor接口onRefresh方法,发布事件ContextRefreshedEvent事件
                     */
                    finishRefresh();
                }
    
                catch (BeansException ex) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Exception encountered during context initialization - " +
                                "cancelling refresh attempt: " + ex);
                    }
    
                    // 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
                    destroyBeans();
    
                    // 将active 设置为false 表示此容器不可用
                    cancelRefresh(ex);
    
                    // Propagate exception to caller.
                    throw ex;
                }
    
                finally {
                    //重置Spring核心中的常见内核缓存,因为我们可能不再需要单例bean的元数据了
                    resetCommonCaches();
                }
            }
        }

    <3>

    org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh

    @Override
        protected void onRefresh() {
            //调用父类的onRefresh
            super.onRefresh();
            try {
                //<4>构建web
                createWebServer();
            }
            catch (Throwable ex) {
                throw new ApplicationContextException("Unable to start web server", ex);
            }
        }

    <4>

    org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#createWebServer

    private void createWebServer() {
            WebServer webServer = this.webServer;
            ServletContext servletContext = getServletContext();
            //触发创建
            if (webServer == null && servletContext == null) {
                StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
                //<5>获得ServletWebServerFactory 如tomcat netty或者自定实现
                ServletWebServerFactory factory = getWebServerFactory();
                createWebServer.tag("factory", factory.getClass().toString());
                //<6>构建webserver
                this.webServer = factory.getWebServer(getSelfInitializer());
                createWebServer.end();
                //实现了SmartLifecycle接口 在容器加载完毕启动web  在容器关闭 关闭web
                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();
        }

    <5>

    org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#getWebServerFactory

     protected ServletWebServerFactory getWebServerFactory() {
            // 获得ServletWebServerFactory实现类的beanName
            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));
            }
            //调用getBean完成初始化 TomcatServletWebServerFactory JettyServletWebServerFactory默认是TomcatServletWebServerFactory
            return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
        }

    <6>

    org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getWebServer

        @Override
        public WebServer getWebServer(ServletContextInitializer... initializers) {
            if (this.disableMBeanRegistry) {
                Registry.disableRegistry();
            }
            Tomcat tomcat = new Tomcat();
            File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
            tomcat.setBaseDir(baseDir.getAbsolutePath());
            Connector connector = new Connector(this.protocol);
            connector.setThrowOnFailure(true);
            tomcat.getService().addConnector(connector);
            customizeConnector(connector);
            tomcat.setConnector(connector);
            tomcat.getHost().setAutoDeploy(false);
            configureEngine(tomcat.getEngine());
            for (Connector additionalConnector : this.additionalTomcatConnectors) {
                tomcat.getService().addConnector(additionalConnector);
            }
            prepareContext(tomcat.getHost(), initializers);
            return getTomcatWebServer(tomcat);
        }
  • 相关阅读:
    新闻发布项目——Servlet类(doRegServlet )
    新闻发布项目——Servlet类(doNewsModifyServlet )
    新闻发布项目——Servlet类(doNewsModifyServlet )
    新闻发布项目——Servlet类(doNewsModifyServlet )
    and or 逻辑组合
    sqoop
    t
    tmp
    临时表 数据在 内存 转移时间 将160秒的创建临时表时间放入定时任务 不到1秒的求和时间 hadoop 引入Hadoop 分布式计算
    /tmp/crontab.tDoyrp: 设备上没有空间 查看文件夹所在分区 磁盘剩余空间 15g的root-mail大文件
  • 原文地址:https://www.cnblogs.com/LQBlog/p/15944872.html
Copyright © 2020-2023  润新知