首页 > 技术文章 > Catalina

wansw 2019-01-09 14:05 原文

Catalina

​ Tomcat里的Server由 org.apache.catalina.startup.Catalina管理。Catalina类里面由 loadstartstop三个方法用来管理整个服务器的生命周期。

1、load:用于根据 conf/server.xml 文件创建Server、并调用Server的init方法进行初始化。

2、start:用于启动服务器。

3、stop:停止服务器。

start、stop方法在内部会调用Server的start和stop方法,load方法调用Server的init方法。

Server的start方法会调用Service中的start方法,Service中的start会调用Connectors和Container中的start方法。

org.apache.catalina.startup.Catalina
// 主要看  Await、load、start、stop方法

Await方法

// 设置 await值,会在start方法中服务器启动完成后来判断是否进入等待状态
public void setAwait(boolean b) {
    await = b;
}

Load方法

// org.apache.catalina.startup.Catalina
public void load() {
    // 已经加载就返回
    if (loaded) {
        return;
    }
    // 设置加载状态
    loaded = true;
    long t1 = System.nanoTime();

    initDirs();
    // Before digester - it may be needed
    initNaming();
    // Create and execute our Digester
    // 通过 digester 解析 server.xml 配置文件
    Digester digester = createStartDigester();
    InputSource inputSource = null;
    InputStream inputStream = null;
    File file = null;
    try {
        try {
            // 指定了 conf/server.xml 
            file = configFile();
            inputStream = new FileInputStream(file);
            inputSource = new InputSource(file.toURI().toURL().toString());
        }
        if (inputStream == null) {
            try {
                inputStream = getClass().getClassLoader()
                    .getResourceAsStream(getConfigFile());
                inputSource = new InputSource
                    (getClass().getClassLoader()
                     .getResource(getConfigFile()).toString());
            }
        }
        if (inputStream == null) {
            // 尝试加载 server-embed.xml 
            try {
                inputStream = getClass().getClassLoader()
                    .getResourceAsStream("server-embed.xml");
                inputSource = new InputSource
                    (getClass().getClassLoader()
                     .getResource("server-embed.xml").toString());
            }
        }
		// 依旧找不到文件,返回
        if (inputStream == null || inputSource == null) {
            return;
        }
        try {
            inputSource.setByteStream(inputStream);
            digester.push(this);
            // 解析 xml
            digester.parse(inputSource);
        }
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                // Ignore
            }
        }
    }
    getServer().setCatalina(this);
    getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
    getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
    // Stream redirection
    initStreams();
    // Start the new server
    try {
        getServer().init();
    }
}

简化后的 load方法:

Digester digester = createStartDigester();
File file = configFile();
inputStream = new FileInputStream(file);
inputSource = new InputSource(file.toURI().toURL().toString());
inputSource.setByteStream(inputStream);  
digester.push(this);  
digester.parse(inputSource);  
getServer().setCatalina(this);  
getServer().init();

​ Digester 查相关资料:Java解析xml主要由DOM4J(一次读取到内存并解析)、SAX(一次解析一部分),digester本身采用SAX的解析方式,并提供了一层包装,对使用者更加友好,后来独立出来成为apache的Commons下面的一个单独的子项目

Start方法

/**
 * Start a new server instance.
 */
public void start() {
    if (getServer() == null) {
        load();
    }
    // Start the new server
    try {
        getServer().start();
    } catch (LifecycleException e) {
        return;
    }
    // 注册shutdown钩子函数
    if (useShutdownHook) {
        if (shutdownHook == null) {
            shutdownHook = new CatalinaShutdownHook();
        }
        Runtime.getRuntime().addShutdownHook(shutdownHook);
        LogManager logManager = LogManager.getLogManager();
        if (logManager instanceof ClassLoaderLogManager) {
            ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                    false);
        }
    }
    if (await) {
        await();
        stop();
    }
}

Stop方法

/**
 * Stop an existing server instance.
 */
public void stop() {
    try {
        // 为了避免调用两次钩子函数,首先移除钩子函数
        if (useShutdownHook) {
            Runtime.getRuntime().removeShutdownHook(shutdownHook);
            LogManager logManager = LogManager.getLogManager();
            if (logManager instanceof ClassLoaderLogManager) {
                ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                    true);
            }
        }
    } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
    }

    // 关闭服务
    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();
    }

}

推荐阅读