tomcat源码分析学习笔记(三)
2014-09-22 00:13
429 查看
——每天的寥寥几笔,坚持下去,将会是一份沉甸甸 的积累。
今天的笔记是针对《tomcat how works》第四章——tomcat的默认连接器来讲的。
1.在上一篇文章我罗列书第三章的源码目录,如下:
其实每章就是在之前简单的基础上进行扩张充实。在第四章里,覆盖了我们自己写的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类启动
(2)其实(1)中的connector.start()还会进行一个操作,就是启动httpConnector线程(这个类也实现了runnable接口)。于是自然而然,start函数一执行,便进入run函数
(3)httpProcessor类。主要功能依旧是封装request,response对象的相关数据,用于触发相关servlet的service方法。封装数据的过程,也就涉及http消息解析,前一篇文章讲到了parseRequest,parseHeaders等,在本文中该类将继续拓展,新增了如parseAcceptLanguage等。
除了上面提到的几个咱们熟悉的方法之外,又新增了assign()和await()方法,下面详细介绍(设计的非常巧妙),主要看看代码里我的文字介绍
(4)还有一个SimpleContainer类,这个就是servlet容器,用来接收request,response对象,解析request得到相应的servlet,根据反射机制,触发改serlvet的service方法
由于涉及到多线程相关知识,理解起来可能有些难度。下一篇我会整理一份多线程相关的笔记以供大家参考。
又周一了,可能接下来几天更新频率不会那么高(学生党要上课),不过依旧会尽量保持进度(各种学长阿里,腾讯的offer纷纷到手,学弟甚是欣羡,必须加倍努力)。。。。
今天的笔记是针对《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纷纷到手,学弟甚是欣羡,必须加倍努力)。。。。
相关文章推荐
- tomcat源码分析学习笔记(一)
- tomcat源码分析学习笔记(五)
- nginx 源码学习笔记(七)——内存分配相关源码分析
- mangos0.9源码分析学习笔记(二)
- bootstrap-modal 学习笔记 源码分析
- Cocos2d-x学习笔记(18)(TestCpp源码分析-2)
- Openstack学习笔记之——Neutron-server服务加载与启动源码分析(三)
- Android源码学习笔记1-短信发送流程分析
- Python源码分析--学习笔记一
- Cocos2d-x学习笔记(17)(TestCpp源码分析-1)
- COCOS2DX 3.0 学习笔记:从源码分析Cocos2dx 3.0 Director类
- nginx 源码学习笔记(七)——内存分配相关源码分析
- OpenCV学习笔记(29)KAZE 算法原理与源码分析(三)特征检测与描述
- Tomcat 7源码学习笔记
- Cocos2d-x学习笔记(19)(TestCpp源码分析-3)
- OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波
- Ogre源码分析与学习笔记-0
- Ogre源码分析与学习笔记-1
- Tomcat源码学习笔记
- bootstrap-modal 学习笔记 源码分析