// If JULI is being used, disable JULI's shutdown hook since // shutdown hooks run in parallel and log messages may be lost // if JULI's hook completes before the CatalinaShutdownHook() LogManagerlogManager= LogManager.getLogManager(); if (logManager instanceof ClassLoaderLogManager) { ((ClassLoaderLogManager) logManager).setUseShutdownHook( false); } }
@Override publicvoidrun() { try { if (getServer() != null) { Catalina.this.stop(); } } catch (Throwable ex) { ExceptionUtils.handleThrowable(ex); log.error(sm.getString("catalina.shutdownHookFail"), ex); } finally { // If JULI is used, shut JULI down *after* the server shuts down // so log messages aren't lost LogManagerlogManager= LogManager.getLogManager(); if (logManager instanceof ClassLoaderLogManager) { ((ClassLoaderLogManager) logManager).shutdown(); } } } }
/** * Stop an existing server instance. */ publicvoidstop() {
try { // Remove the ShutdownHook first so that server.stop() // doesn't get invoked twice if (useShutdownHook) { Runtime.getRuntime().removeShutdownHook(shutdownHook);
// If JULI is being used, re-enable JULI's shutdown to ensure // log messages are not lost LogManagerlogManager= LogManager.getLogManager(); if (logManager instanceof ClassLoaderLogManager) { ((ClassLoaderLogManager) logManager).setUseShutdownHook( true); } } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // This will fail on JDK 1.2. Ignoring, as Tomcat can run // fine without the shutdown hook. }
// Shut down the server try { Servers= getServer(); LifecycleStatestate= 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(); } } catch (LifecycleException e) { log.error("Catalina.stop", e); }
}
移除钩子,调用Server组件的stop、destroy生命周期方法,这个我打算后期专门分析。
阻塞监听关闭指令
1 2 3 4 5 6 7
// Bootstrap中会设置await为true,其目的在于让tomcat在shutdown端口阻塞监听关闭命令 if (await) { //等待收到正确的关机命令,然后返回。 await(); //停止现有的服务器实例。 stop(); }
/** * Wait until a proper shutdown command is received, then return. * 等待收到正确的关机命令,然后返回。 * This keeps the main thread alive - the thread pool listening for http * connections is daemon threads. * 这使主线程保持活动状态——侦听http连接的线程池是守护进程线程。 */ @Override publicvoidawait() { // Negative values - don't wait on port - tomcat is embedded or we just don't like ports //负值——不要等待端口——tomcat是嵌入式的,或者我们只是不喜欢端口 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 = newServerSocket(port, 1, InetAddress.getByName(address)); } catch (IOException e) { log.error("StandardServer.await: create[" + address + ":" + port + "]: ", e); return; }
try { awaitThread = Thread.currentThread();
// Loop waiting for a connection and a valid command //循环等待连接和有效命令 while (!stopAwait) { ServerSocketserverSocket= awaitSocket; if (serverSocket == null) { break; }
// Wait for the next connection Socketsocket=null; StringBuildercommand=newStringBuilder(); try { InputStream stream; longacceptStartTime= System.currentTimeMillis(); try { socket = serverSocket.accept(); socket.setSoTimeout(10 * 1000); // Ten seconds stream = socket.getInputStream(); } catch (SocketTimeoutException ste) { // This should never happen but bug 56684 suggests that // it does. log.warn(sm.getString("standardServer.accept.timeout", Long.valueOf(System.currentTimeMillis() - acceptStartTime)), ste); continue; } catch (AccessControlException ace) { log.warn("StandardServer.accept security exception: " + ace.getMessage(), ace); continue; } catch (IOException e) { if (stopAwait) { // Wait was aborted with socket.close() break; } log.error("StandardServer.await: accept: ", e); break; }
// Read a set of characters from the socket intexpected=1024; // Cut off to avoid DoS attack while (expected < shutdown.length()) { if (random == null) random = newRandom(); expected += (random.nextInt() % 1024); } while (expected > 0) { intch= -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--; } } finally { // Close the socket now that we are done with it try { if (socket != null) { socket.close(); } } catch (IOException e) { // Ignore } }