tomcat源码分析学习笔记(三)

——每天的寥寥几笔,坚持下去,将会是一份沉甸甸 的积累。


今天的笔记是针对《tomcat how works》第四章——tomcat的默认连接器来讲的。


1.在上一篇文章我罗列书第三章的源码目录,如下:

connector:      RequestStream,ResponseStream,ResponseWriter

connnectot.http:HttpConnector,HttpProcessor//前者用于创建serverSocket,监听客户端请求;后者是个关键类,后面单独讲

		HttpRequest,HttpResponse,HttpRequestFacade,HttpResponseFacade
			    //request和response实现了HttpRequestServlet和HttpResponseServlet接口,相关填充数据由下面两个对象提供

		HttpHeader,HttpRequestLine//HTTP消息的头部,请求行封装出的两个实体类

		SocketInputStream//用Socket.InputStream封装出的新的类,实现了读取HTTP消息的头部和请求行,封装到上面两个对象中

		Constants//存一些常量,降低耦合度,便于修改

core:           servletProcessor,staticResourceProcessor
			//这两个类为业务处理类,就servlet而言,会根据connector解析出的处理类类名,用反射机制实例化某servlet类来处理。


其实每章就是在之前简单的基础上进行扩张充实。在第四章里,覆盖了我们自己写的HttpConnector,HttpProcessor,采用了org.apache.catalina.connector.http.HttpConnector和org.apache.catalina.connector.http.HttpProcessor(实现了多处理器线程,可以用来处理不同的客户端请求);并新增了一个处理servlet的容器SimpleContainer。【源码及书籍下载链接:http://pan.baidu.com/s/1ntBhXX3


2.再强调一下,第四章的突破点在于:“多处理线程”,所以需要多线程的相关知识,不是很熟的,建议先给自己充下电。马上,下一篇我也会提供相关笔记的。


3.接下来把处理请求的执行流程给梳理下。

(1)bootstrap类启动

    HttpConnector connector = new HttpConnector();
    SimpleContainer container = new SimpleContainer();
    connector.setContainer(container);
    try {
      connector.initialize();
      connector.start();
解释:
- 创建一个Httpconnector连接器,set一个container容器(这个后面解释);
- 初始化操作:会调用open()函数,而open()函数会调用DefaultServerFactory来生产serverSocket对象(前三章都是直接new出来的,这里用到了工厂)
- start操作:会new出来5个(默认,等于minProcessors)httpProcessor对象(通过调用newProcessor()函数,这个函数会启动httpProcessor自身的线程,即run函数已经跑起来),然后添加到栈中(源码如下)。
    start():
        while (curProcessors < minProcessors) {
            if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
                break;
            HttpProcessor processor = newProcessor();
            recycle(processor);//加入栈中
        }
    newProcessor():
	private HttpProcessor newProcessor() {
        //        if (debug >= 2)
        //            log("newProcessor: Creating new processor");
        HttpProcessor processor = new HttpProcessor(this, curProcessors++);
        if (processor instanceof Lifecycle) {
            try {
                ((Lifecycle) processor).start();//httpProcessor实现了runnable接口,调用start函数直接启动线程,具体源码后面提到
            } catch (LifecycleException e) {
                log("newProcessor", e);
                return (null);
            }
        }
        created.addElement(processor);
        return (processor);
}

(2)其实(1)中的connector.start()还会进行一个操作,就是启动httpConnector线程(这个类也实现了runnable接口)。于是自然而然,start函数一执行,便进入run函数

//极简模式   
 public void run() {
        while (!stopped) {
		//监听客户端请求
		//获取socket对象
            processor.assign(socket);//将Socket对象传到httpProcessor里面处理
        }
    }


(3)httpProcessor类。主要功能依旧是封装request,response对象的相关数据,用于触发相关servlet的service方法。封装数据的过程,也就涉及http消息解析,前一篇文章讲到了parseRequest,parseHeaders等,在本文中该类将继续拓展,新增了如parseAcceptLanguage等。

除了上面提到的几个咱们熟悉的方法之外,又新增了assign()和await()方法,下面详细介绍(设计的非常巧妙),主要看看代码里我的文字介绍

public void run() {
        while (!stopped) {
            Socket socket = await();
//流程从这开始:
//new出这个processor对象的时候已经触发run方法(上面讲过),然后调用await()方法,由于默认available=false,
//因此await方法调用wait()方法,是的线程进入等待状态(等待notify方法唤醒)
//知道httpConnector调用assign方法,是的available=true,然后又notify,使得线程被唤醒,正好available=true,跳出while循环,
//available又被赋成false。此时run中的socket不为null,调用process方法进行处理,最后将封装好的request和response对象作为参数触发serlvet容器的处理程序
            if (socket == null)continue;
            try {
                process(socket);
            } catch (Throwable t) {}
            connector.recycle(this);
        }
    }

private void process(Socket socket) {//极简,删掉了细节部分
        connector.getContainer().invoke(request, response);
    }

synchronized void assign(Socket socket) {
        while (available) {
            try {
                wait();
            } catch (InterruptedException e) {}
        }
        this.socket = socket;
        available = true;
        notifyAll();
    }
private synchronized Socket await() {
        while (!available) {
            try {
                wait();
            } catch (InterruptedException e) {}
        }
        Socket socket = this.socket;
        available = false;
        notifyAll();
        return (socket);
    }


(4)还有一个SimpleContainer类,这个就是servlet容器,用来接收request,response对象,解析request得到相应的servlet,根据反射机制,触发改serlvet的service方法

 

public void invoke(Request request, Response response)throws IOException, ServletException {
      servlet.service((HttpServletRequest) request, (HttpServletResponse) response);//主要就是这个invoke方法,和上的process方法挂钩
    }


由于涉及到多线程相关知识,理解起来可能有些难度。下一篇我会整理一份多线程相关的笔记以供大家参考。

又周一了,可能接下来几天更新频率不会那么高(学生党要上课),不过依旧会尽量保持进度(各种学长阿里,腾讯的offer纷纷到手,学弟甚是欣羡,必须加倍努力)。。。。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值