HowTomcatWorks学习笔记--Tomcat的默认连接器

这本书(How Tomcat Works 中文下载地址)之前就看过,然而也就开了个头就废弃了,所以一直耿耿于怀。这次决定重新开始,在此记录一些学习心得和本书的主要知识点。
所有代码也将托管在GitHub上面。O(∩_∩)O

上节回顾

我们创建了一个connector连接器。

  1. 将之前的程序更加模块化,
  2. 同时解析了HTTP请求,将这些信息封装到HttpRequest,这样Servlet就能够获取到这些信息了。

上一章节的主要工作在于解析HTTP请求上。

概要

主要剖析tomcat的 HttpConnectorHttpProcessor 的源代码。

连接器

一个 Tomcat 连接器必须符合以下条件:

  1. 必须实现接口org.apache.catalina.Connector
  2. 必须创建请求对象,该请求对象的类必须实现接口org.apache.catalina.Request
  3. 必须创建响应对象,该响应对象的类必须实现接口 org.apache.catalina.Response

Connector接口

指的是org.apache.catalina.Connector,在这个接口里,最重要的方法是,
1. getContainer 返回一个容器。
2. setContainer 设置一个容器。
3. createRequest 为前来的 HTTP 请求构造一个请求对象。
4. createResponse 创建一个响应对象。

Connector有很多实现,org.apache.catalina.connector.http.HttpConnector是其中一个。

HttpConnector类

这个类实现的接口有,Connector、Runnable和Lifecycle。
org.apache.catalina.Lifecycle用于维护生命周期。

在前几章节,我们也实现了自己的HttpConnector类,现在来看一下它和Tomcat的有何不同。

  1. 创建ServerSocket方式不同;
  2. 维护HttpProcessor对象池;
  3. 处理HTTP不同。

创建ServerSocket

入口是initialize方法,会判断是否已经初始化过,没有的话就调用open方法。

initialize的主要代码如下:

//...
if (initialized)
            throw new LifecycleException (
                sm.getString("httpConnector.alreadyInitialized"));

        this.initialized=true;
        Exception eRethrow = null;

        // Establish a server socket on the specified port
        try {
            serverSocket = open();
//...

open方法会返回一个ServerSocket实例。它会运用工厂来获取这个实例。主要代码如下:

// ...
// Acquire the server socket factory for this Connector
ServerSocketFactory factory = getFactory();

// If no address is specified, open a connection on all addresses
if (address == null) {
    log(sm.getString("httpConnector.allAddresses"));
    try {
        return (factory.createSocket(port, acceptCount));
    } catch (BindException be) {
        throw new BindException(be.getMessage() + ":" + port);
    }
}

// Open a server socket on the specified address
try {
    InetAddress is = InetAddress.getByName(address);
    log(sm.getString("httpConnector.anAddress", address));
    try {
        return (factory.createSocket(port, acceptCount, is));
// ...      

acceptCount表示连接数量,这里默认是10个。可以设置。

维护HttpProcessor线程池

对我之前我们自己的程序,每次只能处理一个HTTP请求。

在默认的连接器中,HttpConnector拥有一个HttpProcessor对象池,可以处理多个HTTP请求。

对象池是放在Stack中的:

private Stack processors = new Stack();

创建的HttpProcessor实例数量是可以控制的。

介绍几个相关的变量:

  1. minProcessors,最小的实例数量,默认5个。可以设置。
  2. maxProcessors,最大的实例数量,默认20个。可以设置。
  3. curProcessors,当前对象池中的实例数量。

刚开始的时候,会创建minProcessors个实例。

随着时间推移,当请求的数量大于实例的数量时,会创建更多的实例,直到数量抵达maxProcessors个。

如果请求继续增多,将会被忽略。

start方法中创建(这是HttpConnector类的方法,不是用于启动线程的run方法。总是会被搞混。):

//...
if (started)
    throw new LifecycleException
    (sm.getString("httpConnector.alreadyStarted"));
    threadName = "HttpConnector[" + port + "]";
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;

// Start our background thread
threadStart();

// Create the specified minimum number of processors
while (curProcessors < minProcessors) {
    if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
        break;
    HttpProcessor processor = newProcessor();
    recycle(processor);
}
//...

newProcessor方法会创建HttpProcessor实例。

需要注意的是,它在该过程中会直接调用HttpProcessor的start(这是HttpConnector类的方法,不是用于启动线程的run方法。总是会被搞混。)方法。

如下:

private HttpProcessor newProcessor() {
    HttpProcessor processor = new HttpProcessor(this, curProcessors++);
    if (processor instanceof Lifecycle) {
        try {
            ((Lifecycle) processor).start();
        } catch (LifecycleException e) {
            log("newProcessor", e);
            return (null);
        }
    }
    created.addElement(processor);
    return (processor);
}

可以看到,如果创建HttpProcessor对象,就会调用recycle方法。这个方法的内容可以猜想到,就是把processor放到对象池中。

processors.push(processor);

处理HTTP

在上面的start方法中,有一个用于启动线程的方法:threadStart

该方法会,

  1. 调用run方法,创建socket。
  2. 获取HttpProcessor,处理socket。

run方法会执行一个while循环:

// ...
while (!stopped) {
            // Accept the next incoming connection from the server socket
            Socket socket = null;
            try {
                socket = serverSocket.accept();
            // ...

而获取HttpProcessor的主要逻辑如下:

HttpProcessor processor = createProcessor();
if (processor == null) {
    try {
        log(sm.getString("httpConnector.noProcessor"));
        socket.close();
    } catch (IOException e) {
        ;
    }
    continue;
}
processor.assign(socket);

对于HTTP请求的具体处理细节,都在HttpProcessor中。这里会调用它的assign方法。

HttpProcessor类

下一章节继续。


一步一个脚印
本章未完成,(^__^)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值