tomcat源码 分析 Catalina

Posted 众妙之门

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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();
    }
}

 

以上是关于tomcat源码 分析 Catalina的主要内容,如果未能解决你的问题,请参考以下文章

Tomcat7源码分析学习系列之一-----tomcat的真正的启动脚本catalina.bat解析

Tomcat8源码分析系列Tomcat8框架设计

mysql jdbc源码分析片段 和 Tomcat's JDBC Pool

Tomcat源码分析——server.xml文件的加载与解析

Tomcat源码分析

tomcat源码 Connector