1. 程式人生 > >tomcat原始碼 分析 Catalina

tomcat原始碼 分析 Catalina

通過檢視分析啟動指令碼,發現最終呼叫的入口是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();
    }
}