tomcat源码解析(二)

tomcat源码解析(二)–类的加载过程

tocmat的启动入口

   查找Bootstrap类,在其main()上打上断点
在这里插入图片描述

public static void main(String args[]) {

        synchronized (daemonLock) {
            if (daemon == null) {
                // Don't set daemon until init() has completed
                Bootstrap bootstrap = new Bootstrap();
                try {
                    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);
                //加载了http协议以及endpoint
                daemon.load(args);
                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);
        }
    }

首先会进入到 bootstrap.init();方法中
该方法主要是:

  • 创建了三个类加载器
    • 创建commonLoader,如果未创建成果的话,则使用应用程序类加载器作为commonLoader
    • 创建catalinaLoader,父类加载器为commonLoader
    • 创建sharedLoader,父类加载器为commonLoader
  • 设置线程上下文加载器
  • 线程安全的加载tomcat中各个包
    在这里插入图片描述
  • 加载主类Catalina
  • 通过反射获取实例对象
  • 传入sharedLoader 设置它的父类加载器

然后执行bootstrap.load();方法
实际上执行的是Catalina.load();方法

  • 创建的是一个server实例
    • initDirs();和initNaming();只是初始化了一些环境变量,并没有起到其他作用
    • ConfigFileLoader 这个类的作用,是从给定的位置上获取配置文件(例如从文件系统中直接获取改配置文件),所以ConfigFileLoader.setSource()只是将server.xml的文件路径加载进来
    • 获取server.xml文件
    • 创建Digester 用于解析server.xml文件
    • 从文件系统中获取server.xml文件流
    • 进行解析,并存储在Digester 对象中
    • 通过parse 进行解析
      • 将server.xml的文件中的内容进行解析,并且进行绑定
      • 使用到的规则 createStartDigester 所设置对应的规则进行匹配,在缓存中取
      • digester.addObjectCreate(“Server”, “org.apache.catalina.core.StandardServer”, “className”);这个方法表示的含义是,碰到Sever这个标签,则创建一个StandardServer的对象
      • 调用了addChildInternal等方法
      • 只是进行了加载,并未启动子组件
    • 接下来设置server的Catalina 相关属性
    • 初始化流
    • 然后执行StandardServer 的initInternal()方法
      • 将容器托管到JMX,便于运维管理
      • 初始化效用执行人
      • 往jmx中注册全局的String cache,尽管这个cache是全局的,但是如果在同一个jvm中存在多个Server,那么则会注册多个不同名字的StringCache,这种情况在内嵌的tomcat中可能会出现
      • 注册MBeanFactory
      • 初始化 globalNamingResources
        - 将server.xml中的GlobalNamingResources标签创建一个 Mbean对象
      • 寻启动子容器的 init 方法,进入子容器方法中
        - StandardService的initInternal方法
        - 执行StandardEngine的initInternal方法
        - ealm域提供了一种用户密码与web应用的映射关系。
        - 完成 http 和ajp 的初始化,创建CoyoteAdapter 对象,初始化 Http11Protocol,endpoint进行初始化

然后进入到 bootstrap.start();方法中
实际上执行的是Catalina.start();方法

  • 然后执行StandardServer 的startInternal()方法
    • 循环通知到需要监听的事件中
    • globalNamingResources启动
    • 启动所有子容器
      • 执行StandardEngine的startInternal方法
      • 启动左右Container的start方法
        • 获取Cluster 集群信息
        • 获取 Realm 安全策略
        • 寻找该Container下的子容器,并另外线程启动
        • StandardPipeline[StandardEngine[Catalina].StandardHost[localhost]]启动
      • ExecutorService的submit方法会执行然后将结果保存到Future result中
      • 触发Host ContainerBase的call方法,进行子容器启动 然后获取获取Cluster 集群信息,获取 Realm 安全策略,看是否存在子容器,判断是那种部署类型,然后将项目(文件夹,war包或者Context设置下的文件夹进行部署),解析context.xml文件
      • 完成init()方法,然后执行的startInternal()方法,实际上是执行的StandardContext的startInternal方法
        • 跳转到 StandardContext的startInternal方法中
        • 初始化tomcat的ApplicationContext对象并会生成门面对象
        • 添加缺少的组件和资源,判断需要重新加载的资源,
        • 进行项目的启动
        • 解析项目中的web.xml文件
        • 然后启动spi机制将所有jar包下的META-INF/services/javax.servlet.ServletContainerInitializer通过反射实例化进来
        • 合并tomcatWebXml defaults到web.xml里面
        • 添加META-INF/resources/下的静态资源到standardContext
        • 启动完成
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值