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

 

posted @ 2022-02-28 11:30  意犹未尽  阅读(218)  评论(0编辑  收藏  举报