美文网首页
Tomcat 通过 catalina.sh 关闭的流程

Tomcat 通过 catalina.sh 关闭的流程

作者: souco | 来源:发表于2021-06-27 02:02 被阅读0次

1. 启动

以下是 tomcat startup.sh 启动脚本最终调用的启动方法,org.apache.catalina.startup.Catalina#start:

public void start() {
        if (getServer() == null) {
            load();
        }

        if (getServer() == null) {
            log.fatal("Cannot start server. Server instance is not configured.");
            return;
        }

        // Start the new server
        try {
            getServer().start();
        } catch (LifecycleException e) {
            log.fatal(sm.getString("catalina.serverStartFail"), e);
            try {
                getServer().destroy();
            } catch (LifecycleException e1) {
                log.debug("destroy() failed for failed Server ", e1);
            }
            return;
        }

        if (useShutdownHook) {
            if (shutdownHook == null) {
                shutdownHook = new CatalinaShutdownHook();
            }
            Runtime.getRuntime().addShutdownHook(shutdownHook);
        }

        if (await) {
            await();
            stop();
        }
    }

可以看到,上面方法最后是调用了 org.apache.catalina.core.StandardServer#await() 方法:

@Override
    public void await() {
        // Negative values - don't wait on port - tomcat is embedded or we just don't like ports
        if (port == -2) {
            // undocumented yet - for embedding apps that are around, alive.
            return;
        }
        if (port==-1) {
            try {
                awaitThread = Thread.currentThread();
                while(!stopAwait) {
                    try {
                        Thread.sleep( 10000 );
                    } catch( InterruptedException ex ) {
                        // continue and check the flag
                    }
                }
            } finally {
                awaitThread = null;
            }
            return;
        }

        // Set up a server socket to wait on
        try {
            awaitSocket = new ServerSocket(port, 1,
                    InetAddress.getByName(address));
        } catch (IOException e) {
            log.error("StandardServer.await: create[" + address
                               + ":" + port
                               + "]: ", e);
            return;
        }
        ...
    }

这里 StandardServer#await() 方法根据 server.xml 中的 Server 节点 port 配置分了几种情况进行处理:

  • port 为 -2 时,函数直接退出,此时主线程不会阻塞;
  • port 为 -1 时,将等待线程设置为当前线程,并且进入 while 循环,直到 stopAwait 标志位置为 true;
  • port 为其他时,会新建一个 socket 服务端,该 socket 绑定了当前服务器的 IP 以及 Port 端口,随后将等待线程设置为当前线程,并且 socket 进入阻塞监听状态,知道 socket 监听到了 server.xml 中预置的关闭字符串(默认是 SHUTDOWN)

2. 关闭

一般来说,我们常用的有两种关闭 tomcat 的方式,一种是用官方提供的关闭脚本 shutdown.sh 进行关闭,另一种时通过 kill -x [pid] 进行关闭。

2.1. 通过 shutdown.sh 脚本关闭 tomcat

查看 shutdown.sh 脚本的内容,发现最终是调用了 BootStrap#main 方法进行关闭,传的是 "stop" 作为参数。改传参会导致调用 Catalina#stopServer 方法。

具体步骤是:初始化组件 -> 获取 Server 组件 -> 新建 socket 客户端 -> 发送消息至 socket 服务端

显然,这里对应的是 StandardServer#await() 方法的情况3,发送的字符串使得主线程结束阻塞状态,调用各组件的 stop() 和 destroy 方法对资源进行释放。

2.2 kill -x 的方式进行关闭

kill -x 的方式常用的有 kill -9 和 kill -15,相对来说,kill -9 会立即强制结束当前进程,这个操作既方便,但同时也极具破坏性;另外 kill -15 会向进程发送一个 TERM 的中断信号量,再JVM接收到该信号量后,会响应中断,从而结束该进程。JVM在结束当前进程前,会执行一系列名为 shutdownhook 的线程,而 Tomcat 在启动时,会向JVM注册了一个名为 CatalinaShutdownHook 的线程,该线程方法内调用了 Catalina#stop() 方法。

相关文章

网友评论

      本文标题:Tomcat 通过 catalina.sh 关闭的流程

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