在tomcat 的server.xml文件中,頂層Server標簽可以配置一個監(jiān)聽關(guān)閉服務(wù)器命令的端口,一旦接收到SHUTDOWN的請求后,則嘗試關(guān)閉整個tomcat服務(wù)器。
渭濱網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)2013年開創(chuàng)至今到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。具體配置如下:
<Server port="8005" shutdown="SHUTDOWN">
標識監(jiān)聽8005端口,如果接收到的請求為“SHUTDOWN”,那么會觸發(fā)關(guān)閉服務(wù)器的操作。
為了實驗這個端口好不好使,首先我把tomcat啟動了起來,然后在瀏覽器發(fā)送了一個請求: http://localhost:8005/SHUTDOWN
結(jié)果tomcat后臺日志為:
警告: StandardServer.await: Invalid command \'GET /SHUTDOWN HTTP/1.1\' received
并且服務(wù)器沒有關(guān)閉。這次請求收到的內(nèi)容為 GET /SHUTDOWN HTTP/1.1 而不是SHUTDOWN ,查看源碼才發(fā)現(xiàn),這里直接從監(jiān)聽的socket拿的數(shù)據(jù),并沒有做http請求解析,所以收到了一個http get請求的報文。要想正確發(fā)送SHUTDOWN,需要通過socket直接發(fā)送數(shù)據(jù),使用jdk api的操作如下:
java.net.Socket socket = new java.net.Socket("localhost", 8005); socket.getOutputStream().write("SHUTDOWN".getBytes()); socket.getOutputStream().flush(); socket.getOutputStream().close(); socket.close();
這樣tomcat服務(wù)器就能正確關(guān)閉了,日志如下:
七月 17, 2017 12:56:59 下午 org.apache.catalina.core.StandardServer await 信息: A valid shutdown command was received via the shutdown port. Stopping the Server instance. 七月 17, 2017 12:56:59 下午 org.apache.coyote.AbstractProtocol pause 信息: Pausing ProtocolHandler ["http-bio-8080"] 七月 17, 2017 12:56:59 下午 org.apache.coyote.AbstractProtocol pause 信息: Pausing ProtocolHandler ["ajp-bio-8009"] 七月 17, 2017 12:56:59 下午 org.apache.catalina.core.StandardService stopInternal 信息: Stopping service Catalina 七月 17, 2017 12:56:59 下午 org.apache.coyote.AbstractProtocol stop 信息: Stopping ProtocolHandler ["http-bio-8080"] 七月 17, 2017 12:56:59 下午 org.apache.coyote.AbstractProtocol stop 信息: Stopping ProtocolHandler ["ajp-bio-8009"] 七月 17, 2017 12:56:59 下午 org.apache.coyote.AbstractProtocol destroy 信息: Destroying ProtocolHandler ["http-bio-8080"] 七月 17, 2017 12:56:59 下午 org.apache.coyote.AbstractProtocol destroy 信息: Destroying ProtocolHandler ["ajp-bio-8009"]
下面看一下源碼的實現(xiàn):
首先Bootstrap類調(diào)用了Catalina的start()方法啟動服務(wù)器,在start()方法最后,有如下代碼:
/** * Catalina類 * Start a new server instance. */ public void start() { ... if (await) { await(); stop(); } }
變量await在啟動時默認為true,await()方法如下:
/** * Catalina類 * Await and shutdown. */ public void await() { getServer().await(); }
Catalina類中的Server默認實現(xiàn)類為StandardServer,其await()方法如下:
//StandardServer類 //簡化版源碼 public void await() { //如果端口為-2或-1的處理方式 //指定了正常端口 //首先監(jiān)聽此端口 awaitSocket = new ServerSocket(port, 1, InetAddress.getByName(address)); // Loop waiting for a connection and a valid command //循環(huán) while (!stopAwait) { ... //阻塞在這里 等待數(shù)據(jù) socket = serverSocket.accept(); //接收到數(shù)據(jù)后往下執(zhí)行 讀取數(shù)據(jù) // Read a set of characters from the socket int expected = 1024; // Cut off to avoid DoS attack while (expected < shutdown.length()) { if (random == null) random = new Random(); expected += (random.nextInt() % 1024); } while (expected > 0) { int ch = -1; try { ch = stream.read(); } catch (IOException e) { log.warn("StandardServer.await: read: ", e); ch = -1; } // Control character or EOF (-1) terminates loop if (ch < 32 || ch == 127) { break; } command.append((char) ch); expected--; } // Match against our command string boolean match = command.toString().equals(shutdown); //如果接收到的請求為"SHUTDOWN"或其他正確的自定義的字符串 if (match) { log.info(sm.getString("standardServer.shutdownViaPort")); //跳出while循環(huán) await()方法結(jié)束,線程執(zhí)行返回到Catalina類的start()方法,繼續(xù)執(zhí)行Catalina的stop()方法 break; } else log.warn("StandardServer.await: Invalid command \'" + command.toString() + "\' received");
下面看一下Catalina的stop()方法,此方法是真正觸發(fā)tomcat服務(wù)器destroy生命周期的方法:
public void stop() { ... Server s = getServer(); LifecycleState state = s.getState(); if (LifecycleState.STOPPING_PREP.compareTo(state) <= 0 && LifecycleState.DESTROYED.compareTo(state) >= 0) { // Nothing to do. stop() was already called } else { s.stop(); s.destroy(); } }
s即StandardServer,首先判斷s的狀態(tài),該狀態(tài)是一個volatile變量,如果狀態(tài)為正在銷毀,則不進行任何操作;否則,調(diào)用s的stop()和destroy()方法。
stop()和destroy()方法為抽象類LifecycleBase的方法,tomcat中凡是擁有生命周期的組件均繼承自此抽象類,并且這兩個方法使用了 模板方法模式,方法內(nèi)部實現(xiàn)了一部分更改組件狀態(tài)的代碼,之后調(diào)用了抽象方法stopInternal()和stopDestroy(),這倆方法的作用是留給子類去實現(xiàn)。
在StandardServer的stopInternal()方法中,會依次調(diào)用子組件Service的stop()方法:
@Override protected void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); fireLifecycleEvent(CONFIGURE_STOP_EVENT, null); // Stop our defined Services for (int i = 0; i < services.length; i++) { services[i].stop(); } globalNamingResources.stop(); stopAwait(); }
StandardService的stopInternal()方法如下:
protected void stopInternal() throws LifecycleException { // Pause connectors first 首先停止connector再接收新的請求 synchronized (connectorsLock) { for (Connector connector: connectors) { connector.pause(); } } //設(shè)置狀態(tài) setState(LifecycleState.STOPPING); // Stop our defined Container second 關(guān)閉容器,頂層為StandardEngine if (container != null) { synchronized (container) { container.stop(); } } // Now stop the connectors 停止connector synchronized (connectorsLock) { for (Connector connector: connectors) { connector.stop(); } } synchronized (executors) { 關(guān)閉線程池 for (Executor executor: executors) { executor.stop(); } } }
之后,每層組件都是這樣一步一步的向下調(diào)用,鏈式觸發(fā)整個tomcat組件destory的生命周期,完成資源的釋放和銷毀,最終關(guān)閉服務(wù)器。
stop和destroy相似,只是工作不同,有興趣的同志可以繼續(xù)深入研究源碼。
當(dāng)前文章:tomcatserver組件監(jiān)聽shutdown命令關(guān)閉服務(wù)器之源碼分析
轉(zhuǎn)載源于:http://jinyejixie.com/article28/chojjp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開發(fā)、網(wǎng)站策劃、定制開發(fā)、網(wǎng)站排名、面包屑導(dǎo)航、外貿(mào)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)