SpringBoot (7)Tomcat的监听与销毁

生命周期处理器

AbstractApplicationContext->refresh():
    // 最后一步,发布相应的事件
    finishRefresh();
ServletWebServerApplicationContext->finishRefresh():
    super.finishRefresh();
    // web服务开启监听
    WebServer webServer = startWebServer();
    if (webServer != null) {
        // ServletWebServerInitializedEvent事件
        publishEvent(new ServletWebServerInitializedEvent(webServer, this));
    }
    
复制代码

super.finishRefresh()调用的是AbstractApplicationContextfinishRefresh()方法。

initLifecycleProcessor():初始化上下文中的生命周期处理器,若IoC容器中没有的话,则默认为DefaultLifecycleProcessor对象

getLifecycleProcessor().onRefresh():找到IoC容器中实现Lifecycle接口的bean,如果是SmartLifecycle接口实现类且isAutoStartup()方法返回true,isRunning()方法返回false的话,执行start()方法。

publishEvent(new ContextRefreshedEvent(this))ContextRefreshedEvent事件,启动定时任务

监听

service与connector的解绑与重绑

image.png
前情回顾:Tomcat启动时service与connector的解绑

所谓的解绑,就是将service中的connector移除,将两者的关系放到TomcatWebServer的serviceConnectors变量中留作后用

TomcatWebServer->start():
    // 添加之前移除过的connectors
    addPreviouslyRemovedConnectors(); // --1
    ......
    // 检查所有的connector正常启动
    checkThatConnectorsHaveStarted();
TomcatWebServer->addPreviouslyRemovedConnectors():
    Service[] services = this.tomcat.getServer().findServices();
    for (Service service : services) {
        Connector[] connectors = this.serviceConnectors.get(service);
        if (connectors != null) {
            for (Connector connector : connectors) {
                service.addConnector(connector);
            }
            this.serviceConnectors.remove(service);
        }
    }
StandardService->addConnector():
    // service与connector相互绑定
    ......
    // 注意到第一次绑定的时候状态是NEW,此时是STARTED,所以走if方法
    if (getState().isAvailable()) {
        connector.start();
    }
    
复制代码

connector、http11NioProtocol、nioEndpoint的启动

在connector的startInternal()中,Http11NioProtocol启动,它又将NioEndpoint启动

AbstractEndpoint->start():
    bindWithCleanup(); // --1
    startInternal(); // --2
    
NioEndpoint->bind(): // --1
    initServerSocket();
    ......
    // 初始化NioSelectorPool相关属性,与最终写入和输出到客户端有关
    selectorPool.open();
// 终于在这边找到了监听的代码
NioEndpoint->initServerSocket():
    serverSock = ServerSocketChannel.open();
    socketProperties.setProperties(serverSock.socket());
    InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
    // 绑定端口号,注意,如果端口号被占用,将会抛出异常
    serverSock.socket().bind(addr,getAcceptCount());
    // 此时请求就通了
    
NioEndpoint->startInternal(): // --2
    ......
    if ( getExecutor() == null ) {
        // 创建任务执行线程池
        createExecutor();
        pollers = new Poller[getPollerThreadCount()];
        // Poller负责轮训事件栈
        for (int i=0; i<pollers.length; i++) {
            pollers[i] = new Poller();
            Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
            pollerThread.setPriority(threadPriority);
            pollerThread.setDaemon(true);
            pollerThread.start();
        }
        // Acceptor主要用来监听是否有客户端连接进来并接收连接
        startAcceptorThreads();
        // 至此,响应就通了
    }
复制代码

Http11NioProtocol模型之NioEndpoint中介绍过Acceptor、Poller和Executor,作用顺序是从前往后,创建顺序正好与之相反。

总结

所谓的监听,其实就是connector的启动。SpringIoC先实例化与web服务有关的bean,然后再实例化普通bean,Tomcat启动时,普通bean尚未实例化,此时不能开启监听接受请求,因此先将两者解绑,待普通bean实例化完成后,再重新绑定,开启监听,接受请求和响应。

销毁

web服务器销毁的入口方法位于TomcatWebServer->stop():stopTomcat()

销毁分为两步,第一步是停止,第二步是销毁。

与启动一样,也是各组件按照顺序进行的。如下图所示,每个组件的生命周期独立。这里的组件2是组件1的最后一个组件,组件3是组件2的最后一个组件,以此类推。

未命名文件 (4).png

各组件顺序为和大致作用为:

  1. nioEndpoint(关闭监听)
  2. wrapper、context、host、engine
    • engine、host、conext的子组件异步停止,wrapper同步停止
    • 中断背景线程
  3. nioEndpoint、http11NioProtocol、connector
  4. service、server
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享