Tomcat源码分析----Connector初始化与加载

简介: 一个应用服务器的性能很大程度上取决于网络通信模块的实现,因此Connector对于tomcat而言是重中之重。在本章节中以下两个问题会被回答:一个http请求是怎么被tomcat监听到的,会有哪些处理;为什么请求可以有需要通过nginx的,也可以不需要nginx的直接请求到tomcat上?

一个应用服务器的性能很大程度上取决于网络通信模块的实现,因此Connector对于tomcat而言是重中之重。在本章节中以下两个问题会被回答:

  • 一个http请求是怎么被tomcat监听到的,会有哪些处理;
  • 为什么请求可以有需要通过nginx的,也可以不需要nginx的直接请求到tomcat上?

1 Connector配置

通过对Container的初始化分析,我们很自然的会回过头看conf/server.xml中的connector配置。在xml中配置了2个connector。

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

为什么会有多个Connector呢?我们部署服务器的时候,通常会有2种方式:

  • 1 直接部署tomcat,在浏览器中请求http与tomcat直连
  • 2 部署一个nginx作反向代理,tomcat与nginx直连

这就是上面两种配置,通过协议protocol来区分。所以多个connector的好处是通过不同的协议,是tomcat服务器能够随着http的应用场景,服务器架构的升级而兼容起来。

好的,现在配置了2个Connector,那么继续思考一下,Connector是通信过程,如果是你你会怎么设计?显然需要做3件事:

  • (1)监听端口,创建服务端与客户端的链接;
  • (2)获取到客户端请求的socket数据,并对Socket数据进行解析和包装成Http请求数据格式;
  • (3)将包装后的数据交给Container处理。

通过源码来分析,Connector有两个属性:protocolHandler(协议)和adapter(适配器),其中protocolHandler完成的是步骤(1)(2),adapter完成的是步骤(3)。

2 初始化工作

2.1 Connector构造函数

在Connector的构造方法中,通过反射生成protocolHandler.

public Connector(String protocol) {
    setProtocol(protocol);
    // Instantiate protocol handler
    try {
        Class<?> clazz = Class.forName(protocolHandlerClassName);
        this.protocolHandler = (ProtocolHandler) clazz.newInstance();
    } catch (Exception e) {
        log.error(sm.getString(
                "coyoteConnector.protocolHandlerInstantiationFailed"), e);
    }
}

协议的设置在conf/server.xml中配置,由setProtocol来赋值,Tomcat提供了6种协议:
三种不带Ajp的协议,客户端与Tomcat服务器直接连接。
Http11Protocol---------------默认协议,阻塞IO方式的支持http1.1协议
Http11NioProtocol----------非阻塞IO方式的支持http1.1协议
Http11AprProtocol----------使用ARP技术的支持http1.1协议(ARP:Apache portable runtime)
三种带Ajp的协议为定向包协议,即WEB服务器通过 TCP连接和SERVLET容器连接,例如tomcat和Apache、Nginx等前端服务器连接
AjpProtocol--------------------阻塞IO方式的支持Ajp协议
AjpNioProtocol---------------非阻塞IO方式的支持Ajp协议
AjpAprProtocol---------------使用ARP技术的支持Ajp协议
为了便于分析,之对Http11Protocol进行分析,其他的大同小异。在Http11Protocol的构造方法中,对成员变量endpoint和cHandler进行初始化,这两个很重要,后续会继续讲到。
继续到Connector代码中,由前面提到的tomcat启动过程知道,会调用Connector两个方法init和start。而端口的绑定和监听则分别在这两个方法中完成

2.2 Connector的init方法

调用的是initInternal,做了三件事:

  • 1 适配器初始化成CoyoteAdapter;
  • 2 调用Http11Protocol的init方法;
  • 3 调用mapperListener的init方法。
protected void initInternal() throws LifecycleException {

    super.initInternal();
    //TODO:注意,是在在这里初始化的Adapter,将是配置赋值给协议处理类
    adapter = new CoyoteAdapter(this);
    protocolHandler.setAdapter(adapter);
    ……
    try {
        //TODO:在这里初始化http11protocol
        protocolHandler.init();
    } catch (Exception e) {
        ……
    }
    ……
    mapperListener.init();
}

步骤2中Http11Protocol的init方法,最终会调用到其父类AbstractProtocol的init方法,在这个方法里面对endpoint(Http11Protocol使用的是JIoEndPoint)进行了初始化。

public void init() throws Exception {
    ……
    try {
        //endpoint进行了初始化。
        endpoint.init();
    } catch (Exception ex) {
        ……
    }
}

endpoint.init()在AbstractEndpoint中,完成了对需要监听的端口的绑定。

public final void init() throws Exception {
    testServerCipherSuitesOrderSupport();
    if (bindOnInit) {
        bind();//绑定服务端需要监听的端口
        bindState = BindState.BOUND_ON_INIT;
    }
}

在JIoEndpoint的bind()中完成了对端口的绑定。

2.3 Connector的start方法

Connector的启动会调用start方法,在startInternal方法中,

protected void startInternal() throws LifecycleException {
    ……
    setState(LifecycleState.STARTING);//发送STARTING事件
    try {
        protocolHandler.start();//启动端口监听
    }
    ……
    mapperListener.start();//很重要,后面会提到
}

其中,protocolHandler.start();即调用了Http11Protocol的start方法。最终调用了调用了JIoEndpoint的startInternal方法,初始化了连接请求处理的线程池,监听端口的线程(默认200个)

public void startInternal() throws Exception {
    if (!running) {
        ……
        if (getExecutor() == null) {
            createExecutor();//初始化请求处理的线程池
        }
        initializeConnectionLatch();//设置链接线程阈值
        startAcceptorThreads();//初始化监听接收客户端请求的线程
        ……
    }
}

OK,到了现在Connector的启动已经透明化了,Connector的初始化工作其实是根据server.xml的配置,创建了服务端Socket来监听客户端的请求。并初始化了一个线程池来处理接收到的请求。
通过上面的分析,我们可以看到JIoEndpoint是一个阻塞式的IO模型;而若使用Http11NioProtocol协议,则调用的是NioEndpoint,是一个多路复用IO模型。

系列文章直达:

初始化与启动:https://yq.aliyun.com/articles/20169?spm=0.0.0.0.4yGfpo
容器:https://yq.aliyun.com/articles/20172?spm=0.0.0.0.2uPEZi
连接器:https://yq.aliyun.com/articles/20175?spm=0.0.0.0.2uPEZi
一个http请求的经历:https://yq.aliyun.com/articles/20177?spm=0.0.0.0.2uPEZi
重要的设计模式:https://yq.aliyun.com/articles/20179?spm=0.0.0.0.2uPEZi

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