Jetty源码分析
一、启动
SocketListener.start启动,调用new Acceptor(内部类)新开一个线程。线程里监听请求,得到Socket对象(Socket socket=acceptSocket(_listen,_soTimeOut);)
_listen就是ServerSocket。
Acceptor就是线程
二、请求
1.Acceptor.run 每个请求被监听到,就会转为上面的Socket对象. P358
2.调用ThreadPool.run(socket),
再调用PoolThread.run(this,socket)(p347)。_job=socket,再调用notify方法,这会唤醒 org.mortbay.util.ThreadPool.PoolThread.run()方法里的wait方法。继续执行wait的下面代码。_job不为空,_run=_job,这时_run对象不为空。
2.1调用_runPool.handle(_run)
就是ThreadedServer.handle(Socket)。再调用ThreadedServer.handleConnection(socket)。
接收到请求,开始处理。
3.调用createConnection方法,再调用new HttpConnection方法。
3.1将socket的InputStream和OutputStream转为HttpInputStream和HttpOutputStream.
HttpInputStream构造函数中,调用 _realIn=new LineInput(in,bufferSize,StringUtil.__ISO_8859_1) ,其中bufferSize为4096。
3.2构造HttpRequest与HttpResponse,参数为this,即HttpConnection.
connection.handle()
HttpConnection.handleNext()
HttpConnection.readRequest()
HttpRequest.readHeader(LineInput in)
实现:
1) 读消息第一行
line_buffer=in.readLineBuffer(); //把一行读到Buffer里面
decodeRequestLine //提取出方法(Get,Post...),提取http版本号,提取URI
2) 读Header
_header.read(in);通过这一行,将填充header,_header数组length变为n。Read方法调用LineInput里的readLineBuffer方法读取一行。直到读到空行(HttpFields的1119行)返回null。每行是以’\r\n’(windows)或’\r’或’\n’来结束的,源码在LineInput.fillLine这个方法里面。
3) 读请求体
解析Body,得到参数。并不是解析完header后立即解析body,而是在j2ee servlet规范方法 HttpServlet.service(HttpServletRequest request,HttpServletResponse response)第一次调用HttpRequest的getParameters、getParameterNames、getParameter、getParameterValues、getParameterStringArrayMap这些方法时,会调用HttpRequest.extractParameters方法,来解析http的body里面的内容。
HttpRequest的860行: IO.copy(in,bout,max);
in就是socket的InputStream,bout是内存new的ByteArrayOutputStream,max是请求体的长度,也就是请求头的Content-Length。
通过这一行把请求体(请求参数)复制到内存。
HttpRequest的865行: UrlEncoded.decodeTo(content,0,bout.getCount(),_parameters,encoding);
通过这一行把内存中的字节数组解析为Map结构,就是我们应用中的request.getParameterMap、request.getParameter(name)使用的变量。
public HttpInputStream(InputStream in, int bufferSize) { super(null); try { _realIn= new LineInput(in,bufferSize,StringUtil.__ISO_8859_1); } catch(UnsupportedEncodingException e) { Code.fail(e); } this.in=_realIn; }