• spring boot是如何加载Tomcat的


    spring boot是如何加载Tomcat的

    大家都用过spring boot,都知道他启动的时候内置一个Tomcat,但是他是怎么来的,你们知道吗

    这篇博客将带你们走进spring boot的源码,看看spring boot底层是如何加载tomcat的,走起发车!

    1. 方法入口

    入口SpringApplication.run()这个方法大家都很熟悉我就不细讲了,我们从这进去一直找到public ConfigurableApplicationContext run(String... args),然后找到refreshContext这个方法

    public ConfigurableApplicationContext run(String... args) {
          //此处省略
     	  //入口方法
         this.refreshContext(context);
          //此处省略
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    继续往refresh这个方法找,一直跟着refresh找,直到找到ConfigurableApplicationContext抽象类

    private void refreshContext(ConfigurableApplicationContext context) {
        this.refresh((ApplicationContext)context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            } catch (AccessControlException var3) {
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2. SpringContext上下文

    public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
      //此处省略
       //web容器上下文入口
       void refresh() throws BeansException, IllegalStateException;
       //此处省略
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    我们找到他的实现类,我们看到有三个对不对,这时候我们选择AbstractApplicationContext,不要选ServletWebServerApplicationContext,因为ServletWebServerApplicationContextAbstractApplicationContext的子类,我们先看他的抽象方法

    在这里插入图片描述

    进入到AbstractApplicationContext中,我们重点看onRefresh方法

    这是Spring 源码中的核心代码,这是一个模板方法,里面有个很多钩子函数,这里我就不省略代码了,因为这段代码很重要,在这里我们可以看到spring 的生命周期。

    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();
                //加载bean
                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();
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    点进去他是一个空实现

    protected void onRefresh() throws BeansException {
    }
    
    • 1
    • 2

    我们 找到他的实现类ServletWebServerApplicationContext,这是加载web容器的上下文,我们可以明显看到createWebServer就是一个创建web容器的方法

    protected void onRefresh() {
        super.onRefresh();
    
        try {
            //创建web容器
            this.createWebServer();
        } catch (Throwable var2) {
            throw new ApplicationContextException("Unable to start web server", var2);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3. 创建web容器

    我们进去源码继续看,有个getWebServerFactory方法,这是获取webserver工厂类的方法,相信我们离真相不远了

    private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = this.getServletContext();
        if (webServer == null && servletContext == null) {
            //获取webServerr工厂
            ServletWebServerFactory factory = this.getWebServerFactory();
            //通过工厂生成webServer
    		this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
        }
        this.initPropertySources();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    我们继续看可以看到其实我们是获取ServletWebServerFactory的bean,那ServletWebServerFactory具体有什么实现呢

    protected ServletWebServerFactory getWebServerFactory() {
        String[] beanNames = this.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
        //此处省略
    }
    
    • 1
    • 2
    • 3
    • 4

    看到这是不是很清晰啦,我们直接找到TomcatServletWebServerFactory,看他的getWebServer实现
    在这里插入图片描述

    很清晰的看到,这就是tomcat的配置,host,connector之类的,相信以前我们学tomcat的时候都见过

    public WebServer getWebServer(ServletContextInitializer... initializers) {
        if (this.disableMBeanRegistry) {
            Registry.disableRegistry();
        }
    
        Tomcat tomcat = new Tomcat();
        File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
        tomcat.setBaseDir(baseDir.getAbsolutePath());
        Connector connector = new Connector(this.protocol);
        connector.setThrowOnFailure(true);
        tomcat.getService().addConnector(connector);
        this.customizeConnector(connector);
        tomcat.setConnector(connector);
        tomcat.getHost().setAutoDeploy(false);
        this.configureEngine(tomcat.getEngine());
        Iterator var5 = this.additionalTomcatConnectors.iterator();
    
        while(var5.hasNext()) {
            Connector additionalConnector = (Connector)var5.next();
            tomcat.getService().addConnector(additionalConnector);
        }
    
        this.prepareContext(tomcat.getHost(), initializers);
        //启动web容器
        return this.getTomcatWebServer(tomcat);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    4. 启动web容器

    tomcat是在上文中的getTomcatWebServer中启动的,我们再深入进去

    protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
        return new TomcatWebServer(tomcat, this.getPort() >= 0, this.getShutdown());
    }
    
    • 1
    • 2
    • 3

    这是一个TomcatWebServer的构造方法,我们再点进去

    public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
        //此处省略
        //初始化tomcat
        this.initialize();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    进入initialize方法,不用说大家都知道tomcat.start就是启动tomcat

    private void initialize() throws WebServerException {
        logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
        synchronized(this.monitor) {
            try {
                this.addInstanceIdToEngineName();
                Context context = this.findContext();
                context.addLifecycleListener((event) -> {
                    if (context.equals(event.getSource()) && "start".equals(event.getType())) {
                        this.removeServiceConnectors();
                    }
    
                });
                // 启动tomcat
                this.tomcat.start();
                this.rethrowDeferredStartupExceptions();
    
                try {
                    ContextBindings.bindClassLoader(context, context.getNamingToken(), this.getClass().getClassLoader());
                } catch (NamingException var5) {
                }
    
                this.startDaemonAwaitThread();
            } catch (Exception var6) {
                this.stopSilently();
                this.destroySilently();
                throw new WebServerException("Unable to start embedded Tomcat", var6);
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    结语

    这篇文章下来,是不是感觉以前不理解的东西一下子就清晰了呢,这篇文章希望能帮助大家能更简单的去了解源码,学习总是快乐的嘿嘿

  • 相关阅读:
    C++:this指针
    C/C++后端学习秘籍
    【ORACLE Explain 详解】
    系统升级丨酷雷曼6大功能,轻松玩转全景营销
    flink1.10袋鼠云 迁移 flink1.15原生环境 事项汇总
    C - Check The Text(string)
    2010-2023年“国家级大数据综合试验区”试点城市DID匹配数据
    以单颗CMOS摄像头重构三维场景,维悟光子发布单目红外3D成像模组
    Polar bear fishing Privacy Policy
    git:多分支管理
  • 原文地址:https://blog.csdn.net/qq_26751319/article/details/133126990