Tomcat请求处理(二) -- 请求处理框架

书接上文。

当Tomcat的Acceptor监听到有请求到来时,就会结束阻塞,继续进行程序下面的动作。如下面的代码所示:

Java代码 Tomcat请求处理(二) -- 请求处理框架 - guoyang1982 - 游龙

  1. public void run() {   
  2.     while (running) {   
  3.   
  4.         while (paused) {   
  5.             try {   
  6.                 Thread.sleep(1000);   
  7.             } catch (InterruptedException e) {   
  8.             }   
  9.         }   
  10.   
  11.         try {   
  12.             // 开始监听端口   
  13.             Socket socket = serverSocketFactory.acceptSocket(serverSocket);   
  14.             // 初始化Socket   
  15.             serverSocketFactory.initSocket(socket);   
  16.             // 处理Socket   
  17.             if (!processSocket(socket)) {   
  18.                 try {   
  19.                     socket.close();   
  20.                 } catch (IOException e) {   
  21.                 }   
  22.             }   
  23.         } catch (IOException x) {   
  24.             if (running)   
  25.                 log.error(sm.getString("endpoint.accept.fail"), x);   
  26.         } catch (Throwable t) {   
  27.             log.error(sm.getString("endpoint.accept.fail"), t);   
  28.         }   
  29.     }   
  30.   
  31. }  

结束阻塞后,首先是Socket的初始化,由于ServerSocketFactory的实现类DefaultServerSocketFactory并没有扩展initSocket()方法,所以这一步其实是什么都没做的。

接下来程序执行到了processSocket(socket);这一步了,这个方法的源代码如下所示:

Java代码 Tomcat请求处理(二) -- 请求处理框架 - guoyang1982 - 游龙

  1. protected boolean processSocket(Socket socket) {   
  2.     try {   
  3.         if (executor == null) {   
  4.             // 得到一个Work并为它分配这个Socket   
  5.             getWorkerThread().assign(socket);   
  6.         } else {   
  7.             executor.execute(new SocketProcessor(socket));   
  8.         }   
  9.     } catch (Throwable t) {   
  10.         log.error(sm.getString("endpoint.process.fail"), t);   
  11.         return false;   
  12.     }   
  13.     return true;   
  14. }  

executor是一个外部的基于线程池的执行器,先不去考虑它,重点看一下getWorkerThread()和Worker#assign()

getWorkerThread()的源代码如下:

Java代码 Tomcat请求处理(二) -- 请求处理框架 - guoyang1982 - 游龙

  1. protected Worker getWorkerThread() {   
  2.     // 获取一个Worker   
  3.     Worker workerThread = createWorkerThread();   
  4.     while (workerThread == null) {// 如果获取的Worker为Null   
  5.         try {   
  6.             synchronized (workers) {   
  7.                 // 等待workers里边Worker的回收,recycleWorkerThread()中会调用notify通知这个线程结束等待的   
  8.                 workers.wait();   
  9.             }   
  10.         } catch (InterruptedException e) {   
  11.         }   
  12.         // 等待结束,再次获取一个Worker   
  13.         workerThread = createWorkerThread();   
  14.     }   
  15.     return workerThread;   
  16. }  

这里这个createWorkerThread()也就是获取Worker的方法值得研究一下。

Java代码 Tomcat请求处理(二) -- 请求处理框架 - guoyang1982 - 游龙

  1. protected Worker createWorkerThread() {   
  2.     synchronized (workers) {   
  3.         if (workers.size() > 0) {// 如果堆栈中有剩余的Worker   
  4.             // 当前在使用的Worker线程计数   
  5.             curThreadsBusy++;   
  6.             // 将一个Worker推出堆栈   
  7.             return workers.pop();   
  8.         }   
  9.         // 如果堆栈中没有多余的Worker了,那么创建一个。   
  10.         if ((maxThreads > 0) && (curThreads < maxThreads)) {   
  11.             // 如果maxThreads有定义,并且当前的Worker数量小于这个值。   
  12.             // 在recycleWorkerThread()中会将新创建的Worker放入堆栈的   
  13.             curThreadsBusy++;   
  14.             return (newWorkerThread());   
  15.         } else {   
  16.             if (maxThreads < 0) {   
  17.                 // maxThreads没有定义,可以有无限个Worker的情况。   
  18.                 curThreadsBusy++;   
  19.                 return (newWorkerThread());   
  20.             } else {   
  21.                 return (null);   
  22.             }   
  23.         }   
  24.     }   
  25.   
  26. }  

而newWorkerThread()方法还是很好理解的:

Java代码 Tomcat请求处理(二) -- 请求处理框架 - guoyang1982 - 游龙

  1. protected Worker newWorkerThread() {   
  2.     Worker workerThread = new Worker();   
  3.     workerThread.start();   
  4.     return (workerThread);   
  5.   
  6. }  

创建一个Worker线程,并且开启线程。

经过上述的过程,就获得了一个Worker(并且已经开始运行了),那么程序的下一步是调用Worker的assign()方法:

Java代码 Tomcat请求处理(二) -- 请求处理框架 - guoyang1982 - 游龙

  1. synchronized void assign(Socket socket) {   
  2.     // 等待获取完上一个Socket   
  3.     while (available) {   
  4.         try {   
  5.             wait();   
  6.         } catch (InterruptedException e) {   
  7.         }   
  8.     }   
  9.        
  10.     // 保存新的Socket   
  11.     this.socket = socket;   
  12.     available = true;   
  13.     notifyAll();   
  14. }  

这样新的Worker已经有一个Socket对象去处理了,下面来看一下Worker的线程中做了哪些工作。

Java代码 Tomcat请求处理(二) -- 请求处理框架 - guoyang1982 - 游龙

  1. public void run() {   
  2.   
  3.     // 知道收到停止信号,否则一直循环   
  4.     while (running) {   
  5.         // 等待为这个线程设置一个Socket对象   
  6.         Socket socket = await();   
  7.         if (socket == null)   
  8.             continue;   
  9.   
  10.         // 处理请求   
  11.         if (!setSocketOptions(socket) || !handler.process(socket)) {   
  12.             // 关闭Socket   
  13.             try {   
  14.                 socket.close();   
  15.             } catch (IOException e) {   
  16.             }   
  17.         }   
  18.   
  19.         // 回收Worker   
  20.         socket = null;   
  21.         recycleWorkerThread(this);   
  22.   
  23.     }   
  24.   
  25. }  

其中await()用于等待有Socket对象赋给当前的Worker已进行请求处理,代码如下:

Java代码 Tomcat请求处理(二) -- 请求处理框架 - guoyang1982 - 游龙

  1. private synchronized Socket await() {   
  2.   
  3.     // 等待获取Socket   
  4.     while (!available) {   
  5.         try {   
  6.             wait();   
  7.         } catch (InterruptedException e) {   
  8.         }   
  9.     }   
  10.   
  11.     // Socket已经收到   
  12.     Socket socket = this.socket;   
  13.     available = false;   
  14.   
  15.     // 这个notifyAll()是通知assign()中的等待Socket的处理已经开始了,   
  16.     // 可以为这个Worker赋新的值了。   
  17.     notifyAll();   
  18.   
  19.     return (socket);   
  20.   
  21. }  

而setSocketOptions()用于设定一些Socket的参数,如下所示:

Java代码 Tomcat请求处理(二) -- 请求处理框架 - guoyang1982 - 游龙

  1. protected boolean setSocketOptions(Socket socket) {   
  2.     int step = 1;   
  3.     try {   
  4.   
  5.         if (soLinger >= 0) {   
  6.             socket.setSoLinger(true, soLinger);   
  7.         }   
  8.         if (tcpNoDelay) {   
  9.             socket.setTcpNoDelay(tcpNoDelay);   
  10.         }   
  11.         if (soTimeout > 0) {   
  12.             socket.setSoTimeout(soTimeout);   
  13.         }   
  14.   
  15.         step = 2;   
  16.         serverSocketFactory.handshake(socket);   
  17.   
  18.     } catch (Throwable t) {   
  19.         if (log.isDebugEnabled()) {   
  20.             if (step == 2) {   
  21.                 log.debug(sm.getString("endpoint.err.handshake"), t);   
  22.             } else {   
  23.                 log.debug(sm.getString("endpoint.err.unexpected"), t);   
  24.             }   
  25.         }   
  26.         return false;   
  27.     }   
  28.     return true;   
  29. }  

handler.process(socket)封装了处理请求的全过程,下次再详细了解

而最后的recycleWorkerThread()用于回收Worker到堆栈中以备下次使用:

Java代码 Tomcat请求处理(二) -- 请求处理框架 - guoyang1982 - 游龙

  1. protected void recycleWorkerThread(Worker workerThread) {   
  2.     synchronized (workers) {   
  3.         workers.push(workerThread);   
  4.         curThreadsBusy--;   
  5.         workers.notify();   
  6.     }   
  7. }  

好了,请求处理的整个流程大致就是这样的,下次再详细了解请求的真实处理部分,就是handler.process(socket)的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值