tomcat原始碼 分析 Catalina
阿新 • • 發佈:2018-12-08
通過檢視分析啟動指令碼,發現最終呼叫的入口是org.apache.catalina.startup包下面的Bootstrap#main
public static void main(String args[]) { if (daemon == null) { // Don't set daemon until init() has completed Bootstrap bootstrap = new Bootstrap(); try { // 初始化類載入器(這主要是為了要把開發者編寫的各種元件應用(WAR 、EAR 等)部署到容器中,並實現元件應用之間的隔離),建立Catalina例項bootstrap.init(); } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } daemon = bootstrap; } else { // When running as a service the call to stop will be on a new // thread so make sure the correct class loader is used to prevent// a range of class not found exceptions. Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } try { String command = "start"; if (args.length > 0) { command = args[args.length - 1]; } if (command.equals("startd")) { args[args.length- 1] = "start"; daemon.load(args); daemon.start(); } else if (command.equals("stopd")) { args[args.length - 1] = "stop"; daemon.stop(); } else if (command.equals("start")) { daemon.setAwait(true); // 通過反射呼叫Catalina的load方法,載入server.xml配置、初始化Server daemon.load(args); // 通過反射呼叫Catalina的start方法,開啟服務、初始化並開啟一系列元件、子容器 daemon.start(); if (null == daemon.getServer()) { System.exit(1); } } else if (command.equals("stop")) { daemon.stopServer(args); } else if (command.equals("configtest")) { daemon.load(args); if (null == daemon.getServer()) { System.exit(1); } System.exit(0); } else { log.warn("Bootstrap: command \"" + command + "\" does not exist."); } } catch (Throwable t) { // Unwrap the Exception for clearer error reporting if (t instanceof InvocationTargetException && t.getCause() != null) { t = t.getCause(); } handleThrowable(t); t.printStackTrace(); System.exit(1); } }
類org.apache.catalina.startup.Catalina#load分析:
public void load() { ...... //初始化臨時目錄 initDirs(); // Before digester - it may be needed //設定額外的系統屬性 initNaming(); // Create and execute our Digester //Digester是apache commons中的一種xml解析器,處理conf/server.xml //在這個方法裡,讀取serverl.xml時通過反射例項化了standardServer物件 Digester digester = createStartDigester(); ...... try { inputSource.setByteStream(inputStream); digester.push(this); //傳入流到digester解析xml拼成物件 digester.parse(inputSource); } catch (SAXParseException spe) { log.warn("Catalina.start using " + getConfigFile() + ": " + spe.getMessage()); return; } catch (Exception e) { log.warn("Catalina.start using " + getConfigFile() + ": " , e); return; } ...... getServer().setCatalina(this); getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile()); getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile()); // Stream redirection //自定義了System.out.PrintStream,寫了一個子類SystemLogHandler繼承PrintStream,便於多執行緒下的日誌處理 initStreams(); // Start the new server try { //初始化Engine,Executor(用來在connector中管理執行緒池),Connector,mapperListener(用來監聽container的變化的) getServer().init(); } catch (LifecycleException e) { if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) { throw new java.lang.Error(e); } else { log.error("Catalina.start", e); } } long t2 = System.nanoTime(); if(log.isInfoEnabled()) { log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms"); } }
類org.apache.catalina.startup.Catalina#start分析:
public void start() { ...... // Start the new server try { //啟動Engine,Executor,Connector,mapperListener 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 (await) { //呼叫StandardServer的await方法 //建立socket連線的服務端物件ServerSocket; //迴圈等待接收客戶端發出的命令,如果接收到的命令與SHUTDOWN匹配(由於使用了equals,所以shutdown命令必須是大寫的),那麼退出迴圈等待 //執行shutdown.bat的時候,最終使用java命令執行了org.apache.catalina.startup.Bootstrap類中的main方法,引數是stop, //通過呼叫Bootstrap的stopServer方法停止Tomcat,其實質是用反射呼叫catalinaDaemon(型別是Catalina)的stopServer方法。 //catalina通過建立Digester解析server.xml檔案(此處只解析<Server>標籤),以構造出Server容器(此時Server容器的子容器沒有被例項化); //從例項化的Server容器獲取Server的socket監聽埠和地址,然後建立Socket物件連線啟動Tomcat時建立的ServerSocket,最後向ServerSocket傳送SHUTDOWN命令。 //ServerSocket迴圈等待接收到SHUTDOWN命令後,最終呼叫stop方法停止Tomcat。 await(); stop(); } }