Springboot内嵌Tomcat介绍

在SpringBoot出现之前,我们部署一个java应用的方式如下图所示
在这里插入图片描述

而SpringBoot出现之后,内嵌了Tomcat、Jetty这样的Servlet容器,即无需再将应用打包成war部署,将应用打包成jar,直接运行一个jar包就能启动一个web服务。

实现原理

Tomcat-embed

Springboot能够将Tomcat内嵌,是因为Tomcat提供了一套JavaAPI,能够通过Tomcat tomcat = new Tomcat()来创建一个Tomcat容器。只需要引入Maven依赖
在这里插入图片描述

Springboot源码解读

任意一个Springboot应用,都有一个main()函数作为应用的启动方法,里面调用了SpringApplication.run(MyApplication.class, args)

public ConfigurableApplicationContext run(String... args) {
    ConfigurableApplicationContext context = null;
    // 创建spring容器对象 ApplicationContext
    context = createApplicationContext();
    // 做一些初始化容器之前的预备操作
    prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    // 启动spring容器核心方法,包括启动tomcat
    refreshContext(context);
    // 做一些容器启动之后的操作(当前这个方法是空的)
    afterRefresh(context, applicationArguments);
    return context;
}

这里的refreshContext(context),对spring的refresh()进行了封装

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 在容器启动之前做一些准备操作
        prepareRefresh();
        // 通知子类去刷新实例工厂
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // 初始化当前容器中的实例工厂
        prepareBeanFactory(beanFactory);
        try {
            // 允许容器中的基类对实例工厂进行后置处理
            postProcessBeanFactory(beanFactory);
            // 调用实例工厂中的后置处理器
            invokeBeanFactoryPostProcessors(beanFactory);
            // 注册实例的后置处理器,在创建实例时进行拦截
            registerBeanPostProcessors(beanFactory);
            // 初始化消息资源
            initMessageSource();
            // 初始化容器中的事件处理器
            initApplicationEventMulticaster();
            // 初始化一些在特定容器中特殊的实例
            onRefresh();
            // 检查监听器的实例并注册它们
            registerListeners();
            // 实例化所有非懒加载的实例
            finishBeanFactoryInitialization(beanFactory);
            // 最后一步:发布一些响应事件
            finishRefresh();
        }
        catch (BeansException ex) {
        }
        finally {
        }
    }
}

这个方法调用完,spring容器就基本完成了初始化过程,tomcat也是在这个方法内部完成的创建

创建WebServer容器

Springboot内嵌的各种web容器实例,都是在onRefresh()中进行创建的

protected void onRefresh() throws BeansException {
    // For subclasses: do nothing by default.
}
@Override
protected void onRefresh() {
    super.onRefresh();
    createWebServer();
}

private void createWebServer() {
    WebServer webServer = this.webServer;
    ServletContext servletContext = getServletContext();
    if (webServer == null && servletContext == null) {
        // 通过工厂创建WebServer实例
        ServletWebServerFactory factory = getWebServerFactory();
        this.webServer = factory.getWebServer(getSelfInitializer());
    }
}

创建Tomcat实例

@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
    Tomcat tomcat = new Tomcat();
    // 1.创建一个tomcat临时文件路径
    File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
    tomcat.setBaseDir(baseDir.getAbsolutePath());
    // 2.创建连接协议,默认使用HTTP1.1协议,NIO网络模型
    Connector connector = new Connector(this.protocol);
    tomcat.getService().addConnector(connector);
    customizeConnector(connector);
    tomcat.setConnector(connector);
    // 3.创建主机,并关闭热部署
    tomcat.getHost().setAutoDeploy(false);
    // 4.配置引擎
    configureEngine(tomcat.getEngine());
    for (Connector additionalConnector : this.additionalTomcatConnectors) {
        tomcat.getService().addConnector(additionalConnector);
    }
    // 5.初始化TomcatEmbeddedContext
    prepareContext(tomcat.getHost(), initializers);
    // 6.启动tomcat并返回TomcatWebServer对象
    return getTomcatWebServer(tomcat);
}

getTomcatWebServer(tomcat)方法

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

TomcatWebServer(tomcat,autoStart)方法

public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
    Assert.notNull(tomcat, "Tomcat Server must not be null");
    this.tomcat = tomcat;
    this.autoStart = autoStart;
    initialize();
}

initialize()方法

private void initialize() throws WebServerException {
    synchronized (this.monitor) {
        try {
            // 给Engine命名
            addInstanceIdToEngineName();
            // 获取Host中的Context
            Context context = findContext();
            // 绑定Context的生命周期监听器
            context.addLifecycleListener((event) -> {
                if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
                    removeServiceConnectors();
                }
            });
            // 启动tomcat,触发初始化监听器
            this.tomcat.start();
            // 启动过程中子线程的异常从主线程抛出
            rethrowDeferredStartupExceptions();
            // 给当前Context绑定类加载器
            ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
            // tomcat的所有线程都是守护线程,这里启动一个阻塞的非守护线程来确保tomcat能及时停止
            startDaemonAwaitThread();
        }
        catch (Exception ex) {
        }
    }
}

启动Web服务

真正完成springboot启动的方法,依然是由TomcatWebServer这个类完成的,这个类封装了控制整个web服务声明周期的方法,比如initialize(), start(), stop()等等,而这个start()显然就是web服务启动的方法了。

@Override
public void start() throws WebServerException {
    synchronized (this.monitor) {
        Connector connector = this.tomcat.getConnector();
        if (connector != null && this.autoStart) {
            performDeferredLoadOnStartup();
        }
        logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
                + getContextPath() + "'");
    }
}

总结

Spring框架基于接口的设计模式,使得整个框架具有良好的扩展性。
首先,通过继承AbstractApplicationContext,重写onRefresh()对web容器进行初始化,重写finishRefresh()启动web服务。
其次,spring抽象了WebServer接口,提供了“启动”和“停止”两个基本方法,具体方法由不同的web容器各自实现,其中tomcat的实现类叫TomcatWebServer。
最后,TomcatWebServer在构造方法中调用initialize()初始化tomcat,调用start()方法启动web服务,在spring容器销毁之前调用stop()完成tomcat生命周期。

参考:https://mp.weixin.qq.com/s/B0of5OtN89bAn_wSgYNqPw

### Tomcat 的功能 Tomcat 是 Apache 软件基金会开发的一款开源的轻量级应用服务器,在中小型系统和互联网环境中得到了广泛应用。其主要作用是部署和运行 Java Servlet 和 JSP 页面的应用程序。 #### 部署和支持Java应用程序 Tomcat 支持多种类型的Web应用程序,包括但不限于Servlets, JSP (JavaServer Pages), WebSocket等技术构建的应用。这些特性使得它成为许多企业内部网以及外部网站的理想选择[^1]。 #### 动态内容处理能力 对于动态生成的内容,尤其是基于Java的企业级应用来说,Tomcat 提供了一个稳定可靠的执行环境。通过集成JVM(Java虚拟机),可以高效地解析并响应HTTP请求中的业务逻辑部分[^2]。 ### 应用场景 #### 传统Web应用和服务端API接口 当项目规模适中且侧重于常规网页交互或RESTful风格的服务端点暴露时,选用Tomcat作为容器来承载这类负载是非常合适的。它可以轻松应对大多数日常流量模式下的读写操作,并保持良好的稳定性与安全性。 ```java // 示例:简单的Servlet实现 @WebServlet("/hello") public class HelloServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("<html><body>"); out.println("<h1>Hello from Tomcat!</h1>"); out.println("</body></html>"); } } ``` #### 结合其他工具提升效能 为了优化性能表现或是适应特定的技术框架要求,常常会看到Tomcat与其他软件协同工作的案例。例如,在面对大量静态资源分发的任务上,通常建议前端采用Nginx负责反向代理及缓存管理;而在后台继续利用Tomcat的强大Java支持来进行复杂计算或数据库访问等工作。 #### 开发测试阶段的选择 由于配置简单灵活、启动迅速等特点,很多开发者倾向于在本地机器上安装单实例版本用于调试目的。这不仅有助于加速迭代周期内的编码验证过程,同时也便于团队成员之间共享一致的基础设置[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值