Tomcat启动过程

Tomcat启动过程,第1张

Tomcat启动过程 解析server.xml
  1. Catalina catalina = new Catalina(); // 没做其他事情
  2. catalina.setAwait(true); 
  1. 以下步骤是解析servler.xml
  2. StandardServer server = new StandardServer();  // 没做其他事情
  1. catalina.setServer(server);
  2. server.addLifecycleListener(...);
  1. StandardService service = new StandardService(); // 没做其他事情
  2. server.addService(service);
  1. Connector connector = new Connector();  // 会根据配置初始化protocolHandler
    1. endpoint = new JIoEndpoint();    // 初始化Endpoint, JioEndpoint中会setMaxConnections(0);
    2. cHandler = new Http11ConnectionHandler(this);  // 
    1. ((JIoEndpoint) endpoint).setHandler(cHandler);    // endpoint对应的连接处理器
  1. service.addConnector(connector);   
  2. Engine engine = new StandardEngine();  // pipeline.setBasic(new StandardEnginevalve());
  1. service.setContainer(engine);
  2. Host host = new StandardHost();    // pipeline.setBasic(new StandardHostValve());
  1. engine.addChild(host);
  2. Context context = new StandardContext();  // pipeline.setBasic(new StandardContextValve());
  1. host.addChild(context);
  2. engine.setParentClassLoader(Catalina.class.getClassLoader()); // 实际调用的是Containerbase.setParentClassLoader方法,设置属性parentClassLoader为shareClassLoader
  1. server.setCatalina(catalina);
  2. server.init();   // 开始初始化
  1. catalina.start();  // 开始启动

总结

解析server.xml最主要的作用就是

  1. 把server.xml中定义的节点都生成对应的java对象,比如在解析某一个Host节点时就会对应生成一个StandardHost对象
  2. 把server.xml中定义的节点的层级关系解析出来,比如StandardContext对象.addChild(StandardHost对象)
  1. 设置每个容器的pipeline的基础Valve

初始化

Tomcat初始化主要做了以下事情:

  1. 将StandardServer实例注册到JMX
  2. 将StringCache实例注册到JMX
  1. 将StandardService实例注册到JMX
  2. container.init(); // 对StandardEngine进行初始化
    1. 初始化startStopExecutor线程池,用来启动子容器的
  1. connector.init(); // 对Connector进行初始化
    1. adapter = new CoyoteAdapter(this);
    2. protocolHandler.setAdapter(adapter);
    1. protocolHandler.init(); // 初始化协议处理器
      1. endpoint.init();    // 初始化协议处理器对应的endpoint,默认在初始化的时候就会bind
        1. endpoint.bind()
          1. serverSocketFactory = new DefaultServerSocketFactory(this);
          2. serverSocket = serverSocketFactory.createSocket(getPort(), getBacklog(), getAddress());
    1. mapperListener.init(); // 没做什么其他的

总结

初始化做得事情比较少,最重要的可能就是endpoint的bind的了

启动
  1. catalina.start()
  2. getServer().start();
    1. fireLifecycleEvent(CONFIGURE_START_EVENT, null);
    2. services[i].start();
      1. container.start(); // 启动StandardEngine
        1. results.add(startStopExecutor.submit(new StartChild(children[i]))); // 每个Childrean容器(StandardHost)用单独的线程启动
          1. results.add(startStopExecutor.submit(new StartChild(children[i]))); // 每个Childrean容器(StandardContext)用单独的线程启动
            1. 以下为一个应用的启动过程
            2. 生成一个WebappLoader
            1. 启动WebappLoader
              1. 生成WebappClassLoader
              2. 将/WEB-INF/classes和/WEB-INF/lib目录作为loaderRepositories,后面应用如果加载类就从这两个目录加载
            1. fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
              1. 解析web.xml文件
                1. 创建WebXml对象
                2. 解析web.xml文件内容设置WebXml对象属性
                  1. WebXML对象有以下几个主要属性
                  2. Map servlets
                  1. Map servletMappings
                  2. Map filters
                  1. Set filterMaps
                1. 收集ServletContainerInitializers
                2. 将WebXML对象中的信息配置到Context对象中
                  1. context.addFilterDef(filter);
                  2. context.addFilterMap(filterMap);
                  1. context.addApplicationListener(listener);
                  2. 遍历每个ServletDef,生成一个Wrapper,context.addChild(wrapper);
            1. 调用ServletContainerInitializers
          1. 上面会启动在server.xml中定义的Context,接下来会启动webapp文件夹下面的Context,是通过HostConfig触发的,调用HostConfig的start()
            1. deployApps();
              1. deployDescriptors(configbase, configbase.list()); // 描述符部署
              2. deployWARs(appbase, filteredAppPaths); // war包部署
              1. deployDirectories(appbase, filteredAppPaths); // 文件夹部署
                1. 生成Context对象
                2. context.setName(cn.getName());
                1. context.setPath(cn.getPath());
                2. host.addChild(context);  // 这里会启动context,启动Context就会执行和上面类似的步骤
        1. threadStart(); // 启动一个background线程
      1. executor.start();  // 启动线程池, 如果用的默认连接池,这里不会启动
      2. connector.start(); // 启动请求连接器
        1. protocolHandler.start(); // 启动接收连接
          1. endpoint.start(); // 启动Endpoint
            1. 如果没有配置Executor,就创建一个默认的Executor
            2. 初始化connectionLimitLatch
            1. 如果是NIO,则运行Poller线程
            2. 运行Acceptor线程
        1. mapperListener.start();
          1. 主要初始化Mapper对象,Mapper对象的结构层级如下
            1. Mapper中有属性Host[] hosts
            2. Host中有属性ContextList contextList
            1. ContextList中有属性Context[] contexts
            2. Context中有属性ContextVersion[] versions
            1. ContextVersion中有如下属性
              1. Wrapper[] exactWrappers,保存需要根据Servlet名字精确匹配的Wrapper
              2. Wrapper[] wildcardWrappers,保存需要根据Servlet名字匹配以("/*")结尾的Wrapper
              1. Wrapper[] extensionWrappers,保存需要根据Servlet名字匹配以("*.")开始的Wrapper
              2. Wrapper中有如下两个属性
                1. name,Wrapper的名字
                2. object,真实的Wrapper的对象
  1. catalina.await();  // 使用ServerSocket来监听shutdown命令来阻塞
  2. catalina.stop();  // 如果阻塞被解开,那么开始停止流程

总结

启动做的事情就比较多了,主要分为以下几大步骤

启动容器

启动容器主要是部署应用,部署应用分为两部分:

  1. 部署server.xml中定义的Context
  2. 部署webapp文件夹下的Context

部署一个应用主要分为以下步骤

  1. 生成Context对象,server.xml中定义的Context在解析server.xml时就已经生成了,webapp文件夹下的是在部署之前生成的
  2. 为每个应用生成一个WebappClassLoader
  1. 解析web.xml
  2. 设置Context对象中的属性,比如有哪些Wrapper

启动Connector

主要是:

  1. 启动Endpoint开始接收请求
  2. 构造Mapper对象,用来处理请求时,快速解析出当前请求对应哪个Context,哪个Wrapper

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5697287.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存