zoukankan      html  css  js  c++  java
  • 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");
        }
    }

    digester.parse解析xml创建对象的时候相关操作:

    1.会绑定HostConfig到StandardHost的lifecycleListeners,然后执行StandardHost.ini时会调用HostConfig.deployApps去查找目录和XML找到Context

    类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();
        }
    }
  • 相关阅读:
    前端代码规范
    AD 对联
    leaflet 入门笔记
    在Mac OS X上安装Git
    在Mac上开启C的新征程
    Python编程基础
    GitHub的使用(Git Shell)
    《网页设计心理学》Susan M.Weinschenk 小结精粹
    【问题】做图片验证码时乱码了,在header前加上ob_clean()就能神奇的显示?!
    --allow-file-access-from-files 命令的使用
  • 原文地址:https://www.cnblogs.com/grasp/p/10074239.html
Copyright © 2011-2022 走看看