Tomcat - Tomcat 8.5.55 启动过程源码分析阶段二_load加载初始化

简介: Tomcat - Tomcat 8.5.55 启动过程源码分析阶段二_load加载初始化

20200524232834382.png

启动流程分析


20200530135838330.png

20200528164120805.png


Pre


Tomcat - Tomcat 8.5.55 启动过程源码分析阶段一_init实例化Bootstrap

我们分析了 init 的主要功能,实例化Bootstrap , 调用init 通过反射调用


Catalina#setParentClassLoader ,后面调用的load 和 start方法 均为 反射调用的Catalina对象的load和start 方法。


load 加载初始化

总体预览



20200530115453665.png


源码解析


20200531121615413.png


load()

我们梳理关键脉络


  // Digester对象  用于解析 server.xml
  Digester digester = createStartDigester();
  // tomcat的配置文件  server.xml
   file = configFile();
 // 解析 xml  重点关注返回的对象  root
   digester.parse(inputSource);


进到这个parse方法

 /**
     * Parse the content of the specified input source using this Digester.
     * Returns the root element from the object stack (if any).
     *
     * @param input Input source containing the XML data to be parsed
     * @return the root object
     * @exception IOException if an input/output error occurs
     * @exception SAXException if a parsing exception occurs
     */
    public Object parse(InputSource input) throws IOException, SAXException {
        configure();
        getXMLReader().parse(input);
        return root;
    }


20200530141750725.png


那我们看下我们source目录下的精简后的server.xml

20200530142208102.png


结合tomcat总体的架构图,套娃结构 , server-service-----connector/container-----engine-----host-----context-----wrapper


20200524234428508.png

刚才debug出来的root对象是不是很好理解了呢?

我们看下LifeCycle接口的继承关系, tomcat类的命名其实是很规范的 StandardXXXX


20200530142518997.png


那继续看下 root对象的 及 配置文件的关系


20200530145048460.png


Server初始化

继续往下跟

//  Servier初始化
  getServer().init();


调用的是 LifeCycle的init接口 , 跟进去可以看到是进入到了 LifeCycleBase这个抽象类的init方法

在init方法中 ,调用

 // 初始化的关键方法 (抽象方法 交由子类实现  设计模式中的模板模式)
   initInternal();


可以看到这个方法是抽象方法 , 具体的实现由继承了LifeCycleBase这个抽象的子类实现具体的业务逻辑。

这里使用了模板模式 . 我们看下LifeCycleBase抽行类的具体实现


20200531153536904.png


很规范的实现 ,每个组件实例化 都要从LifeCycleBase中走一遍 ,自行实现 init方法。

既然这里是Server, 那到StandardServer # initInternal 中看下

最重要的代码 实例化Service

 for (Service service : services) {
            service.init();
        }


这里可以看出来,Service 支持配置多个,不过通常情况下,不建议这么做。 想配置多个,干嘛不多起个tomcat呢?


Service初始化

同样的模板模式 , 还是会调用到 StandardService # initInternal ,精简后的核心代码如下

 @Override
    protected void initInternal() throws LifecycleException {
        super.initInternal();
        if (engine != null) {
            engine.init();
        } 
        // Initialize our defined Connectors
        synchronized (connectorsLock) {
            for (Connector connector : connectors) { 
                    connector.init();    
            }
        }
    }

可以看到 StandardService # initInternal 中 主要干了两件事儿 engine.init 和 connector.init


Engine初始化

同样的老一套,模板模式, 跟进到 StandardEngine # initInternal

    @Override
    protected void initInternal() throws LifecycleException { 
        getRealm();
        super.initInternal();
    }

可以看到调用的是父类的 initInternal , 父类 ContainerBase

   @Override
    protected void initInternal() throws LifecycleException {
        BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
        startStopExecutor = new ThreadPoolExecutor(
                getStartStopThreadsInternal(),
                getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
                startStopQueue,
                new StartStopThreadFactory(getName() + "-startStop-"));
        startStopExecutor.allowCoreThreadTimeOut(true);
        super.initInternal();
    }


干了件啥事儿? 无非就是实例化了一个连接池startStopExecutor , 这个线程池的主要作用是在后面的start方法中使用。Engine可以配置多个Host,这个连接池的作用主要是为了并行初始化Host


Connector 初始化


继续 StandardService # initInternal , 接着 Connector 实例化, for循环嘛 ,一看就是支持配置多个Connector

   for (Connector connector : connectors) { 
                    connector.init();    
            }


Connector# initInternal

核心代码

 @Override
    protected void initInternal() throws LifecycleException {
        super.initInternal();
        // Initialize adapter 并绑定 protocolHandler
        adapter = new CoyoteAdapter(this);
        protocolHandler.setAdapter(adapter);
         // protocolHandler初始化,主要是 内部EndPoint的初始化 
         protocolHandler.init();
    }


CoyoteAdapter 对应tomcat架构图,是不是就是 Http 和 Servlet 之间用来做转换的那个Adapter ?

protocolHandler.setAdapter(adapter) 绑定


20200524234428508.png



继续看

// protocolHandler初始化,主要是 内部EndPoint的初始化 
   protocolHandler.init();


进入 AbstractHttp11Protocol # init

  @Override
    public void init() throws Exception { 
        for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {
            configureUpgradeProtocol(upgradeProtocol);
        }
        super.init();
    }


关注 super.init(); 调用抽象父类AbstractProtocol ,精简后的代码如下


 @Override
    public void init() throws Exception {
        String endpointName = getName();
        endpoint.setName(endpointName.substring(1, endpointName.length()-1));
        endpoint.setDomain(domain);
      // 通信端点的初始化
        endpoint.init();
    }


核心: endpoint.init();

调用 AbstractEndpoint # init

public void init() throws Exception {
        if (bindOnInit) {
            bind();
            bindState = BindState.BOUND_ON_INIT;
        }
    }


重点是bind 方法

NioEndpoint ,我们这里的版本是tomcat8+, 默认的是NIO

精简后的核心代码如下:

 @Override
    public void bind() throws Exception {
        if (!getUseInheritedChannel()) {
            // 获取NIO 通道
            serverSock = ServerSocketChannel.open();
            socketProperties.setProperties(serverSock.socket());
            InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
            // 绑定端口,但尚未使用accept获取客户端连接
            serverSock.socket().bind(addr,getAcceptCount());
        } 
    }


至此,load方法完毕


小结


通过一层层的分析,tomcat套娃式的设计,使用模板模式,一层层的初始化 ,是不是有了更深刻的理解了呢?

oad完了,接下来我们来看下start阶段都干了啥事儿,继续下一篇 ~


相关文章
|
3月前
|
监控 Java 应用服务中间件
Spring Boot整合Tomcat底层源码分析
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置和起步依赖等特性,大大简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是其与Tomcat的整合。
85 1
|
5月前
|
监控 网络协议 应用服务中间件
【Tomcat源码分析】从零开始理解 HTTP 请求处理 (第一篇)
本文详细解析了Tomcat架构中复杂的`Connector`组件。作为客户端与服务器间沟通的桥梁,`Connector`负责接收请求、封装为`Request`和`Response`对象,并传递给`Container`处理。文章通过四个关键问题逐步剖析了`Connector`的工作原理,并深入探讨了其构造方法、`init()`与`start()`方法。通过分析`ProtocolHandler`、`Endpoint`等核心组件,揭示了`Connector`初始化及启动的全过程。本文适合希望深入了解Tomcat内部机制的读者。欢迎关注并点赞,持续更新中。如有问题,可搜索【码上遇见你】交流。
【Tomcat源码分析】从零开始理解 HTTP 请求处理 (第一篇)
|
5月前
|
人工智能 前端开发 Java
【Tomcat源码分析】启动过程深度解析 (二)
本文深入探讨了Tomcat启动Web应用的过程,重点解析了其加载ServletContextListener及Servlet的机制。文章从Bootstrap反射调用Catalina的start方法开始,逐步介绍了StandardServer、StandardService、StandardEngine、StandardHost、StandardContext和StandardWrapper的启动流程。每个组件通过Lifecycle接口协调启动,子容器逐层启动,直至整个服务器完全启动。此外,还详细分析了Pipeline及其Valve组件的作用,展示了Tomcat内部组件间的协作机制。
【Tomcat源码分析】启动过程深度解析 (二)
|
5月前
|
前端开发 Java 应用服务中间件
【Tomcat源码分析 】"深入探索:Tomcat 类加载机制揭秘"
本文详细介绍了Java类加载机制及其在Tomcat中的应用。首先回顾了Java默认的类加载器,包括启动类加载器、扩展类加载器和应用程序类加载器,并解释了双亲委派模型的工作原理及其重要性。接着,文章分析了Tomcat为何不能使用默认类加载机制,因为它需要解决多个应用程序共存时的类库版本冲突、资源共享、类库隔离及JSP文件热更新等问题。最后,详细展示了Tomcat独特的类加载器设计,包括Common、Catalina、Shared、WebApp和Jsp类加载器,确保了系统的稳定性和安全性。通过这种设计,Tomcat实现了不同应用程序间的类库隔离与共享,同时支持JSP文件的热插拔。
【Tomcat源码分析 】"深入探索:Tomcat 类加载机制揭秘"
|
5月前
|
设计模式 应用服务中间件 容器
【Tomcat源码分析】Pipeline 与 Valve 的秘密花园
本文深入剖析了Tomcat中的Pipeline和Valve组件。Valve作为请求处理链中的核心组件,通过接口定义了关键方法;ValveBase为其基类,提供了通用实现。Pipeline则作为Valve容器,通过首尾相连的Valve链完成业务处理。StandardPipeline实现了Pipeline接口,提供了详细的Valve管理逻辑。通过对代码的详细分析,揭示了模板方法模式和责任链模式的应用,展示了系统的扩展性和模块化设计。
【Tomcat源码分析】Pipeline 与 Valve 的秘密花园
|
5月前
|
设计模式 人工智能 安全
【Tomcat源码分析】生命周期机制 Lifecycle
Tomcat内部通过各种组件协同工作,构建了一个复杂的Web服务器架构。其中,`Lifecycle`机制作为核心,管理组件从创建到销毁的整个生命周期。本文详细解析了Lifecycle的工作原理及其方法,如初始化、启动、停止和销毁等关键步骤,并展示了LifecycleBase类如何通过状态机和模板模式实现这一过程。通过深入理解Lifecycle,我们可以更好地掌握组件生命周期管理,提升系统设计能力。欢迎关注【码上遇见你】获取更多信息,或搜索【AI贝塔】体验免费的Chat GPT。希望本章内容对你有所帮助。
|
Java 应用服务中间件 容器
Tomcat源码分析----一个http请求的经历
本章节对http请求到tomcat服务端,从监听到处理过程展现给大家。
12884 0
|
4月前
|
安全 应用服务中间件 网络安全
Tomcat如何配置PFX证书?
【10月更文挑战第2天】Tomcat如何配置PFX证书?
336 7