• 让天下没有难学的技术
    多数学员都来自推荐,这就是口碑的力量

java开发技术Tomcat系统架构分析

1. Connector 组件

Connector 组件是 Tomcat 中两个核心组件之一,它的主要任务是负责接收浏览器的发过来的 tcp 连接请求,创建一个 Request 和 Response 对象分别用于和请求端交换数据,然后会产生一个线程来处理这个请求并把产生的 Request 和 Response 对象传给处理这个请求的线程,处理这个请求的线程就是 Container 组件要做的事了。

由于这个过程比较复杂,大体的流程可以用下面的顺序图来解释:

1.1. Connector 处理一次请求顺序图

Tomcat系统架构分析

Tomcat5 中默认的 Connector 是 Coyote,这个 Connector 是可以选择替换的。Connector 最重要的功能就是接收连接请求然后分配线程让 Container 来处理这个请求,所以这必然是多线程的,多线程的处理是 Connector 设计的核心。Tomcat5 将这个过程更加细化,它将 Connector 划分成 Connector、Processor、Protocol, 另外 Coyote 也定义自己的 Request 和 Response 对象。

下面主要看一下 Tomcat 中如何处理多线程的连接请求,先看一下 Connector 的主要类图:

 Connector 的主要类图

Tomcat系统架构分析

看一下 HttpConnector 的 Start 方法:

 HttpConnector.Start

public void start() throws LifecycleException {
if (started)
throw new LifecycleException
(sm.getString(“httpConnector.alreadyStarted”));
threadName = “HttpConnector[” + port + “]”;
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
threadStart();
while (curProcessors < minProcessors) {
if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
break;
HttpProcessor processor = newProcessor();
recycle(processor);
}
}

threadStart() 执行就会进入等待请求的状态,直到一个新的请求到来才会激活它继续执行,这个激活是在 HttpProcessor 的 assign 方法中,这个方法是代码如下 :

HttpProcessor.assign

synchronized void assign(Socket socket) {
while (available) {
try {
wait();
} catch (InterruptedException e) {
}
}
this.socket = socket;
available = true;
notifyAll();
if ((debug >= 1) && (socket != null))
log(” An incoming request is being assigned”);
}

创建 HttpProcessor 对象是会把 available 设为 false,所以当请求到来时不会进入 while 循环,将请求的 socket 赋给当期处理的 socket,并将 available 设为 true,当 available 设为 true 是 HttpProcessor 的 run 方法将被激活,接下去将会处理这次请求。

Run 方法代码如下:

HttpProcessor.Run

public void run() {
while (!stopped) {
Socket socket = await();
if (socket == null)
continue;
try {
process(socket);
} catch (Throwable t) {
log(“process.invoke”, t);
}
connector.recycle(this);
}
synchronized (threadSync) {
threadSync.notifyAll();
}
}

解析 socket 的过程在 process 方法中,process 方法的代码片段如下:

HttpProcessor.process

private void process(Socket socket) {
boolean ok = true;
boolean finishResponse = true;
SocketInputStream input = null;
OutputStream output = null;
try {
input = new SocketInputStream(socket.getInputStream(),connector.getBufferSize());
} catch (Exception e) {
log(“process.create”, e);
ok = false;
}
keepAlive = true;
while (!stopped && ok && keepAlive) {
finishResponse = true;
try {
request.setStream(input);
request.setResponse(response);
output = socket.getOutputStream();
response.setStream(output);
response.setRequest(request);
((HttpServletResponse) response.getResponse())
.setHeader(“Server”, SERVER_INFO);
} catch (Exception e) {
log(“process.create”, e);
ok = false;
}
try {
if (ok) {
parseConnection(socket);
parseRequest(input, output);
if (!request.getRequest().getProtocol().startsWith(“HTTP/0”))
parseHeaders(input);
if (http11) {
ackRequest(output);
if (connector.isChunkingAllowed())
response.setAllowChunking(true);
}
}
。。。。。。
try {
((HttpServletResponse) response).setHeader
(“Date”, FastHttpDateFormat.getCurrentDate());
if (ok) {
connector.getContainer().invoke(request, response);
}
。。。。。。
}
try {
shutdownInput(input);
socket.close();
} catch (IOException e) {
;
} catch (Throwable e) {
log(“process.invoke”, e);
}
socket = null;
}

当 Connector 将 socket 连接封装成 request 和 response 对象后接下来的事情就交给 Container 来处理了。

想要了解跟多关于java培训课程内容欢迎关注尚硅谷java培训,尚硅谷除了这些技术文章外还有免费的高质量大 java培训课程视频供广大学员下载学习。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注