SpringBoot是如何实现main方法启动Web项目的?

一、问题解析

在Spring Boot中,通过SpringApplication类的静态方法run来启动Web项目。当我们在main方法中调用run方法时,Spring Boot使用一个内嵌的Tomcat服务器,并将其配置为处理Web请求。

当应用程序启动时,Spring Boot会自动扫描应用程序中所有的Spring组件,并使用默认的配置来启动内嵌的Tomcat服务器。在默认情况下,Spring Boot会自动配置大部分的Web开发所需的配置,包括请求处理、视图解析、静态资源处理等。

这样,在应用程序启动后,我们就可以通过Web浏览器访问应用程序了。例如,在默认情况下,可以通过访问http://localhost:8080 来访问应用程序的首页。

但是,很多人都会忽略一个关键的步骤(网上很多介绍SpringBoot启动流程的都没提到),那就是Web容器的启动,及Tomcat的启动其实也是在这个步骤。

实现原理

在SpringBoot的启动流程中,会调用SpringApplication.run方法,这个方法会有一个步骤进行上下文刷新(refreshContext),然后这个过程中,会调用一个关键的方法onRefresh。

调用链:SpringApplication.run -> refreshContext -> refresh -> onRefresh

在refresh-> onRefresh中,这里会调用到ServletWebServerApplicationContext的onRefresh中:

 


@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) {
        StartupStep createWebServer = getApplicationStartup().start("spring.boot.webserver.create");
        ServletWebServerFactory factory = getWebServerFactory();
        createWebServer.tag("factory", factory.getClass().toString());
        this.webServer = factory.getWebServer(getSelfInitializer());
        createWebServer.end();
        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();
}

这里面的createWebServer方法中,调用到factory.getWebServer(getSelfInitializer());的时候,factory有三种实现,分别是JettyServletWebServerFactory、TomcatServletWebServerFactory、UndertowServletWebServerFactory这三个,默认使用TomcatServletWebServerFactory。

TomcatServletWebServerFactory的getWebServer方法如下,这里会创建一个Tomcat 

@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());
    for (LifecycleListener listener : this.serverLifecycleListeners) {
        tomcat.getServer().addLifecycleListener(listener);
    }
    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);
}

在最后一步getTomcatWebServer(tomcat);的代码中,会创建一个TomcatServer,并且把他启动:

protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
    return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
}


public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
    Assert.notNull(tomcat, "Tomcat Server must not be null");
    this.tomcat = tomcat;
    this.autoStart = autoStart;
    this.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(tomcat) : null;
    initialize();
}

 接下来在initialize中完成了tomcat的启动。

image.png

扩展知识

修改web服务器

除了默认的Tomcat之外,Spring Boot还支持内嵌Jetty和Undertow服务器。

我们可以通过修改pom.xml文件中的依赖项来切换到其他的内嵌Web服务器。例如,如果我们想使用Undertow作为内嵌服务器,我们可以将以下依赖项添加到pom.xml文件中: 

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

除了修改依赖项之外,我们还可以通过在application.properties或application.yml文件中设置server属性来配置内嵌Web服务器。例如,如果我们想将端口号从默认的8080更改为9090,我们可以在application.properties文件中添加以下属性:

server.port=9090

除了端口号之外,我们还可以在这里设置其他的Web服务器属性,例如上下文路径、SSL证书等。更多有关配置内嵌Web服务器的信息,可以参考Spring Boot官方文档。 

 二、粉丝福利

我是浮生,一个工作十四年经验的Java程序员!

最近很多同学问我有没有java学习资料,我根据我从小白到架构师多年的学习经验整理出来了一份80W字面试解析文档、简历模板、学习路线图、java必看学习书籍 、 需要的小伙伴 可以关注我
公众号:“ 
灰灰聊架构 ”, 回复暗号:“ 321 ”即可获取

  • 28
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值