【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
jetty接受到链接请求,首先要解析请求;jetty中定义了一个HttpParser类来解析http。类中的部分定义如下
// States
public static final int STATE_START=-14;
public static final int STATE_FIELD0=-13;
public static final int STATE_SPACE1=-12;
public static final int STATE_STATUS=-11;
public static final int STATE_URI=-10;
public static final int STATE_SPACE2=-9;
public static final int STATE_END0=-8;
public static final int STATE_END1=-7;
public static final int STATE_FIELD2=-6;
public static final int STATE_HEADER=-5;
public static final int STATE_HEADER_NAME=-4;
public static final int STATE_HEADER_IN_NAME=-3;
public static final int STATE_HEADER_VALUE=-2;
public static final int STATE_HEADER_IN_VALUE=-1;
public static final int STATE_END=0;
public static final int STATE_EOF_CONTENT=1;
public static final int STATE_CONTENT=2;
public static final int STATE_CHUNKED_CONTENT=3;
public static final int STATE_CHUNK_SIZE=4;
public static final int STATE_CHUNK_PARAMS=5;
public static final int STATE_CHUNK=6;
public static final int STATE_SEEKING_EOF=7;
private final EventHandler _handler;
private final Buffers _buffers; // source of buffers
private final EndPoint _endp;
private Buffer _header; // Buffer for header data (and small _content)
private Buffer _body; // Buffer for large content
private Buffer _buffer; // The current buffer in use (either _header or _content)
从这定义的状态来看,http解析是顺序执行的,从请求头到content,并把解析出来的http头和内容保存在自定义的Buffer里;
再来看具体的parse方法:
/**
* Parse until {@link #STATE_END END} state.
* If the parser is already in the END state, then it is {@link #reset reset} and re-parsed.
* @throws IllegalStateException If the buffers have already been partially parsed.
*/
public void parse() throws IOException
{
if (_state==STATE_END)
reset();
if (_state!=STATE_START)
throw new IllegalStateException("!START");
// continue parsing
while (_state != STATE_END)
if (parseNext()<0)
return;
}
没错,关键的解析是在parseNext方法中的,由于这个方法实在太大,就不贴出来了;
也就是解析完http头再解析http体;初始化各种如下:
/* ------------------------------------------------------------ */
public AbstractHttpConnection(Connector connector, EndPoint endpoint, Server server)
{
super(endpoint);
_uri = StringUtil.__UTF8.equals(URIUtil.__CHARSET)?new HttpURI():new EncodedHttpURI(URIUtil.__CHARSET);
_connector = connector;
HttpBuffers ab = (HttpBuffers)_connector;
_parser = newHttpParser(ab.getRequestBuffers(), endpoint, new RequestHandler());
_requestFields = new HttpFields();
_responseFields = new HttpFields();
_request = new Request(this);
_response = new Response(this);
_generator = newHttpGenerator(ab.getResponseBuffers(), endpoint);
_generator.setSendServerVersion(server.getSendServerVersion());
_server = server;
}
我关心的是request的信息什么时候被设置;方法就在AbstractHttpConnection类中,部分代码如下
protected void handleRequest() throws IOException
{
boolean error = false;
String threadName=null;
Throwable async_exception=null;
try
{
if (LOG.isDebugEnabled())
{
threadName=Thread.currentThread().getName();
Thread.currentThread().setName(threadName+" - "+_uri);
}
// Loop here to handle async request redispatches.
// The loop is controlled by the call to async.unhandle in the
// finally block below. If call is from a non-blocking connector,
// then the unhandle will return false only if an async dispatch has
// already happened when unhandle is called. For a blocking connector,
// the wait for the asynchronous dispatch or timeout actually happens
// within the call to unhandle().
解析完就是一个jetty的httpRequest了;
剩下还有一个我们关心的session;jetty的Request中有两个属性与session相关,一个是_session,另一个是_sessionManager;
其中setSession()方法只在两个地方调用了,两个调用的地方都在SessionHandler里;
1、检查requst cookies中的值,或者uri中的参数
/**
* Look for a requested session ID in cookies and URI parameters
*
* @param baseRequest
* @param request
*/
protected void checkRequestedSessionId(Request baseRequest, HttpServletRequest request)
2、再一个
@Override
public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
SessionManager old_session_manager = null;
HttpSession old_session = null;
HttpSession access = null;
try
{
old_session_manager = baseRequest.getSessionManager();
old_session = baseRequest.getSession(false);
if (old_session_manager != _sessionManager)
{
// new session context
baseRequest.setSessionManager(_sessionManager);
baseRequest.setSession(null);
checkRequestedSessionId(baseRequest,request);//即1中指的那个方法
}
比较这两个地方发现,只有在SessionHandler的doScope方法中设置session;
其中_sessionManager是存储和维护session的地方;默认是HashSessionManager存储在内存中,重启即失效;
在看看Request中的_seesionManager的set方法,也只有SessionHander的doScope调用了;也就是说整个过程只有在这里给设置_sessionManager。那么每一次请求过来,Request中的_sessionManager必然是null的;
然后reqest的SessionManager别设置为SessionHandler的_sessionManager;而这个_sessionManager只有在SessionHander的构造函数中调用setSessionManager方法;所有要找到SessionHander在什么时候初始化的;
- -! 由于找了好久还是不知道怎么初始化的,大概是执行链中获取的;ScopedHandler中的_nextScope被设置为SessionHandler; 乏力。。。
-----------------
那么就不管怎么初始化SessionHandler中的_sessionMananger的了,只知道最后request中的_sessionManager回等于该_sesionManager;
还是来看看requet的getSesion方法吧:
/*
* @see javax.servlet.http.HttpServletRequest#getSession()
*/
public HttpSession getSession()
{
return getSession(true);
}
以及
public HttpSession getSession(boolean create)
{
if (_session != null)
{
if (_sessionManager != null && !_sessionManager.isValid(_session))
_session = null;
else
return _session;
}
if (!create)
return null;
if (_sessionManager == null)
throw new IllegalStateException("No SessionManager");
_session = _sessionManager.newHttpSession(this);
HttpCookie cookie = _sessionManager.getSessionCookie(_session,getContextPath(),isSecure());
if (cookie != null)
_connection.getResponse().addCookie(cookie);
return _session;
}
得知调用getSession方法会在sessionManager中创建一个session实例并保存起来;也同时向response中写入cookie;
如果当前requet已经有sesion直接返回该session;
来源:oschina
链接:https://my.oschina.net/u/782865/blog/505533