美文网首页
Spring源码之六-onRefresh()方法

Spring源码之六-onRefresh()方法

作者: 憩在河岸上的鱼丶 | 来源:发表于2022-08-06 21:10 被阅读0次

    原文地址:https://segmentfault.com/a/1190000041493352

    今天带大家解读Spirng源码之六的onRefresh()方法,这是refresh()的其中的一个方法,看似是一个空方法,实则他是非常非常重要的,对于提高Spring的扩展性。

    老规矩,先贴上Spring的核心方法refresh()方法的源码,以便读者可以丝滑入戏。

    @Override
        public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // Prepare this context for refreshing.
                //1、刷新前的准备
                prepareRefresh();
    
                // Tell the subclass to refresh the internal bean factory.
                //2、将会初始化 BeanFactory、加载 Bean、注册 Bean
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                // Prepare the bean factory for use in this context.
                //3、设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
                prepareBeanFactory(beanFactory);
    
                try {
                    //4、模板方法
                    // Allows post-processing of the bean factory in context subclasses.
                    postProcessBeanFactory(beanFactory);
    
                    // Invoke factory processors registered as beans in the context.
                    //执行BeanFactory后置处理器
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // 5、Register bean processors that intercept bean creation.
                    //注册bean后置处理器
                    registerBeanPostProcessors(beanFactory);
    
                    // Initialize message source for this context.
                    //国际化
                    initMessageSource();
    
                    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();
    
                    // Initialize other special beans in specific context subclasses.
                    //6、模板方法--springboot实现了这个方法
                    onRefresh();
    
                    // Check for listener beans and register them.
                    //7、注册监听器
                    registerListeners();
    
                    // Instantiate all remaining (non-lazy-init) singletons.
                    //8、完成bean工厂的初始化**方法**********************************************
                    finishBeanFactoryInitialization(beanFactory);
    
                    //9、 Last step: publish corresponding event.
                    finishRefresh();
                }
    
                catch (BeansException ex) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Exception encountered during context initialization - " +
                                "cancelling refresh attempt: " + ex);
                    }
    
                    // Destroy already created singletons to avoid dangling resources.
                    destroyBeans();
    
                    // Reset 'active' flag.
                    cancelRefresh(ex);
    
                    // Propagate exception to caller.
                    throw ex;
                }
    
                finally {
                    // Reset common introspection caches in Spring's core, since we
                    // might not ever need metadata for singleton beans anymore...
                    resetCommonCaches();
                }
            }
        }
    
    onRefresh()是模板方法,具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
    

    这是onRefresh()的主要作用,那么文章到这里就结束了,感谢阅读!

    开玩笑,只说作用不举例那和耍流氓没有什么区别,接下来就以Spirng的典型实现Springboot来举例。

    该方法的执行时机是Spring已经加载好了一些特殊的bean(内置的一些bean,实现了bean工厂后置处理器的类)之后,在实例化单例bean之前。让我们来看Springboot是怎么调用这个模板方法的。

    一路的点击Springboot的核心入口run()方法,一路找到了我们今天的主角,Spring的refresh()方法中的onRefresh()方法。

    点击查看Springboot的onRresh()的实现方法。

    有两个包路径含有boot的,一定就是Spirngboot的实现方法。

    image.png

    这是Spirng的onRresh()的实现方法。

    image.png

    比对一下Spirng的onRresh()和SpirngbootRefersh的实现类对比,Springboot多了两个实现类,ReactiveWebServerApplicationContext类和ServletWebServerApplicationContext类。

    我们分别查看这两个实现的onRresh()方法都做了什么?

    方法名都是createWebServer()方法,以为这两个方法都是一个方法,仔细一看发现并不是。

    image.png

    两个createWebServer()方法做了什么呢?我们debug进去搂一眼。

    ReactiveWebServerApplicationContext类的onRresh()方法并没有执行到,见名知意应该是跟webServer管理相关的,限于篇幅问题,留个坑暂时放在吧。

    image.png

    ServletWebServerApplicationContext类的onRefresh()方法执行到了,我们进去一探究竟。

        private void createWebServer() {
            WebServer webServer = this.webServer;
            ServletContext servletContext = getServletContext();
            //第一次进来webServer servletContext都是null,会进到if分支里面
            if (webServer == null && servletContext == null) {
                //这里就会来查找ServletWebServerFactory,也就是web容器的工厂,具体看下getWebServerFactory()方法,
                // 还是ServletWebServerApplicationContext这个类的方法
                //创建了 TomcatServletWebServerFactory 类
                ServletWebServerFactory factory = getWebServerFactory();
                //创建 Tomcat
                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();
        }
    

    核心应该是 factory.getWebServer(getSelfInitializer()),这个方法是创建了一个容器。都有哪些容器呢?

    image.png

    我们看一下他的实现类有Jetty、Mock、Tomcat*,Tomcat就不必提了,Jetty略有耳闻和Tomcat并列的容易。

    那mock是什么呢,带着求知的态度百度一下,没看懂,过!

    image.png

    我们还是重点看Tomcat。进去看TomcatServletWebServerFactory的实现类,new了一个Tomcat的对象,并做了一些Tomcat的设置,什么协议、端口......等等。

    @Override
    public WebServer getWebServer(ServletContextInitializer... initializers) {
       if (this.disableMBeanRegistry) {
          Registry.disableRegistry();
       }
       //创建 Tomcat
       Tomcat tomcat = new Tomcat();
       File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
       tomcat.setBaseDir(baseDir.getAbsolutePath());
       // 同步非阻塞io协议
       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);
       //这里会创建 TomcatWebServer 实例, 并返回
       return getTomcatWebServer(tomcat);
    }
    

    好了,到此就把spirng的模板方法onRefresh()在Springboot中是怎么用的说说清楚了,顺道把Tomcat是怎么内嵌到Springboot中简要的讲解了一下。

    貌似有点跑题了,讲onRefresh()方法呢,结果在springboot中饶了一大圈。不过,能让读者更好的理解Spirng和Springboot的关系,能认真的读读也是大有裨益的。

    也是真的感叹Spirng作者们的功力之强,Spirng的扩展性有多少的强大。

    相关文章

      网友评论

          本文标题:Spring源码之六-onRefresh()方法

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