设为首页 收藏本站
查看: 444|回复: 0

[经验分享] Tomcat请求处理(二) -- 请求处理框架

[复制链接]

尚未签到

发表于 2017-2-1 14:15:59 | 显示全部楼层 |阅读模式
书接上文。
当Tomcat的Acceptor监听到有请求到来时,就会结束阻塞,继续进行程序下面的动作。如下面的代码所示:
public void run() {
while (running) {
while (paused) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
try {
// 开始监听端口
Socket socket = serverSocketFactory.acceptSocket(serverSocket);
// 初始化Socket
serverSocketFactory.initSocket(socket);
// 处理Socket
if (!processSocket(socket)) {
try {
socket.close();
} catch (IOException e) {
}
}
} catch (IOException x) {
if (running)
log.error(sm.getString("endpoint.accept.fail"), x);
} catch (Throwable t) {
log.error(sm.getString("endpoint.accept.fail"), t);
}
}
}

结束阻塞后,首先是Socket的初始化,由于ServerSocketFactory的实现类DefaultServerSocketFactory并没有扩展initSocket()方法,所以这一步其实是什么都没做的。
接下来程序执行到了processSocket(socket);这一步了,这个方法的源代码如下所示:
protected boolean processSocket(Socket socket) {
try {
if (executor == null) {
// 得到一个Work并为它分配这个Socket
getWorkerThread().assign(socket);
} else {
executor.execute(new SocketProcessor(socket));
}
} catch (Throwable t) {
log.error(sm.getString("endpoint.process.fail"), t);
return false;
}
return true;
}

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

protected Worker getWorkerThread() {
// 获取一个Worker
Worker workerThread = createWorkerThread();
while (workerThread == null) {// 如果获取的Worker为Null
try {
synchronized (workers) {
// 等待workers里边Worker的回收,recycleWorkerThread()中会调用notify通知这个线程结束等待的
workers.wait();
}
} catch (InterruptedException e) {
}
// 等待结束,再次获取一个Worker
workerThread = createWorkerThread();
}
return workerThread;
}

这里这个createWorkerThread()也就是获取Worker的方法值得研究一下。
protected Worker createWorkerThread() {
synchronized (workers) {
if (workers.size() > 0) {// 如果堆栈中有剩余的Worker
// 当前在使用的Worker线程计数
curThreadsBusy++;
// 将一个Worker推出堆栈
return workers.pop();
}
// 如果堆栈中没有多余的Worker了,那么创建一个。
if ((maxThreads > 0) && (curThreads < maxThreads)) {
// 如果maxThreads有定义,并且当前的Worker数量小于这个值。
// 在recycleWorkerThread()中会将新创建的Worker放入堆栈的
curThreadsBusy++;
return (newWorkerThread());
} else {
if (maxThreads < 0) {
// maxThreads没有定义,可以有无限个Worker的情况。
curThreadsBusy++;
return (newWorkerThread());
} else {
return (null);
}
}
}
}

而newWorkerThread()方法还是很好理解的:
protected Worker newWorkerThread() {
Worker workerThread = new Worker();
workerThread.start();
return (workerThread);
}

创建一个Worker线程,并且开启线程。
经过上述的过程,就获得了一个Worker(并且已经开始运行了),那么程序的下一步是调用Worker的assign()方法:
synchronized void assign(Socket socket) {
// 等待获取完上一个Socket
while (available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// 保存新的Socket
this.socket = socket;
available = true;
notifyAll();
}

这样新的Worker已经有一个Socket对象去处理了,下面来看一下Worker的线程中做了哪些工作。
public void run() {
// 知道收到停止信号,否则一直循环
while (running) {
// 等待为这个线程设置一个Socket对象
Socket socket = await();
if (socket == null)
continue;
// 处理请求
if (!setSocketOptions(socket) || !handler.process(socket)) {
// 关闭Socket
try {
socket.close();
} catch (IOException e) {
}
}
// 回收Worker
socket = null;
recycleWorkerThread(this);
}
}

其中await()用于等待有Socket对象赋给当前的Worker已进行请求处理,代码如下:
private synchronized Socket await() {
// 等待获取Socket
while (!available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// Socket已经收到
Socket socket = this.socket;
available = false;
// 这个notifyAll()是通知assign()中的等待Socket的处理已经开始了,
// 可以为这个Worker赋新的值了。
notifyAll();
return (socket);
}

而setSocketOptions()用于设定一些Socket的参数,如下所示:
protected boolean setSocketOptions(Socket socket) {
int step = 1;
try {
if (soLinger >= 0) {
socket.setSoLinger(true, soLinger);
}
if (tcpNoDelay) {
socket.setTcpNoDelay(tcpNoDelay);
}
if (soTimeout > 0) {
socket.setSoTimeout(soTimeout);
}
step = 2;
serverSocketFactory.handshake(socket);
} catch (Throwable t) {
if (log.isDebugEnabled()) {
if (step == 2) {
log.debug(sm.getString("endpoint.err.handshake"), t);
} else {
log.debug(sm.getString("endpoint.err.unexpected"), t);
}
}
return false;
}
return true;
}

handler.process(socket)封装了处理请求的全过程,下次再详细了解
而最后的recycleWorkerThread()用于回收Worker到堆栈中以备下次使用:
protected void recycleWorkerThread(Worker workerThread) {
synchronized (workers) {
workers.push(workerThread);
curThreadsBusy--;
workers.notify();
}
}

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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-336202-1-1.html 上篇帖子: tomcat 6 el表达式的问题 下篇帖子: 深入Tomcat 下Jsp乱码处理方法
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表