Tomcat处理请求流程源码解析
⽂章⽬录
前⾔
开局两张图,内容全靠编。本⽂主要分析tomcat的请求解析流程,包括request和response对象的⽣成,continer和pipeline的关系,filterChain的处理⼀直到最后到servlet,其实应该⾸先分析Tomcat的线程模型,⽆奈别⼈写的太好,推荐这篇。
filterChain
⼀、Request对象的⽣成
⽰Tomcat中request对象主要是通过parseRequestLine()和parseHeaders()⽅法进⾏解析的,具体代码参考源码,太长了就不展⽰了。在Http11Processor中的service⽅法中完成了对请求⾏和请求头的分析,inputbuffer只能顺序读取⼀次,剩余部分就是请求体,依旧设置在request的inputbuffer中,所以获取请求体的内容可以通过inputbuffer。
//解析请求⾏
if (!inputBuffer.parseRequestLine(keptAlive)) {
if (ParsingRequestLinePhase() == -1) {
return SocketState.UPGRADING;
} else if (handleIncompleteRequestLineRead()) {
break;
}
}
/
/解析请求头
if (!http09 && !inputBuffer.parseHeaders()) {
// We've read part of the request, don't recycle it
// instead associate it with the socket
openSocket = true;
readComplete = false;
break;
}
⼆、cookie和session
tomcat通过在请求头中获取cookie,⼊⼝⽅法为parseCookieHeader()
servlet和tomcat的关系
public void parseCookieHeader(MimeHeaders headers,
ServerCookies serverCookies) {
if (headers == null) {
// nothing to process
return;
}
// process each "cookie" header
int pos = headers.findHeader("Cookie", 0);
while (pos >= 0) {
MessageBytes cookieValue = Value(pos);
if (cookieValue != null && !cookieValue.isNull() ) {
if (Type() != MessageBytes.T_BYTES ) {
if (log.isDebugEnabled()) {
Exception e = new Exception();
// TODO: Review this in light of HTTP/2
log.debug("Cookies: Parsing cookie as String. Expected bytes.", e);
}
}
if (log.isDebugEnabled()) {
log.debug("Cookies: Parsing b[]: " + String());
}
ByteChunk bc = ByteChunk();
Cookie.Bytes(), bc.getOffset(), bc.getLength(),
serverCookies);
}
// search from the next position
pos = headers.findHeader("Cookie", ++pos);
}
}
2.session
服务器通过SessionId区分区分不同的会话,使⽤SessionId获取对应Session中的内容。通过Session()⽅法触发,当⽆法获取到session时,会创建⼀个新的session。此时我们考虑⼀下web开发中Servlet三⼤域对象的应⽤,分别是request,session和context,request就是⼀次请求,
session中数据受两个因素影响:(1)客户端cookie中存储的sessionid,客户端关闭,sessionid丢失,数据丢失;(2)服务器端session超时,导致数据丢失,context的⽣命周期伴随着整个web应⽤。session的存储使⽤的是ConcurrentHashMap,保证并发下的数据安全。
protected Session doGetSession(boolean create) {
// There cannot be a session if no context has been assigned yet
Context context = getContext();
if (context == null) {
return null;
}
// Return the current session if it exists and is valid
if ((session != null) && !session.isValid()) {
session = null;
}
if (session != null) {
return session;
}
// Return the requested session if it exists and is valid
Manager manager = Manager();
if (manager == null) {
return null;      // Sessions are not supported
}
if (requestedSessionId != null) {
try {
/
/查session是否存在
session = manager.findSession(requestedSessionId);
。。。。。。。
}
// Create a new session if requested and the response is not committed
if (!create) {
return null;
}
boolean trackModesIncludesCookie =
throw new String("coyoteRequest.sessionCreateCommitted"));
}
// Re-use session IDs provided by the client in very limited
// circumstances.
String sessionId = getRequestedSessionId();
。。。。。。省略
//创建新的session
session = ateSession(sessionId);
// Creating a new session cookie based on that session  //cookie中添加sessionid
if (session != null && trackModesIncludesCookie) {
Cookie cookie = ateSessionCookie(
context, IdInternal(), isSecure());
response.addSessionCookieInternal(cookie);
}
if (session == null) {
return null;
}
session.access();
return session;
}
三.pipeline和value
Tomcat容器中内容的执⾏是通过⼀个管道来控制的,如图所⽰的四种容器都持有⼀个Pipeline⽤以执⾏预定义好的任务,任务装载在Value中,被称为阀。通过CoyoteAdapter开始调⽤,下⾯给出调⽤过程中的重点代码。基于责任链模式进⾏了多次调⽤,最终调⽤到filterChain的doFilter⽅法。
public void service(Request req, Response res)
throws Exception {
try {
// Parse and set Catalina and configuration specific
// request parameters 完成了对session,cookie等参数的解析
postParseSuccess = postParseRequest(req, request, res, response);
if (postParseSuccess) {
//check valves if we support async
request.setAsyncSupported(
// Calling the container
request, response);
}
}
getNext().invoke(request, response);
。。。。。
filterChain.doFilter
(Request(), Response());
四.filterChain
filterChain的doFilter也是基于责任链模式,不断重复调⽤,最终通过servlet的service⽅法,重点代码如下。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。