大飞带你深入理解Tomcat(六)

作者:叩丁狼教育王一飞,高级讲师。转载请注明出处。
接上篇,代码已经能处理简单的请求,但走读一下代码,会发现这些代码非常粗糙,可改动的地方非常多,本篇先对HttpServlet进行优化
上上篇中HttpServer类担当2个责任,
1:负责接收客户端发起的请求
2:解析并响应请求。
按照单一类设计原则应该给予拆分,参考tomcat源码,HttpServer类可以分为HttpConnector类和HttpProcessor类,前者仅负责接收各类请求,后者解析并响应请求。同时添加一个启动类Boostrap
新增类:HttpConnector
/** * 负责监听端口,接收请求信息,原先HttpServer类拆分而成 */ public class HttpConnector implements Runnable {// 停止记号 private boolean stopped; // 处理 private String scheme = "http"; public String getScheme() { return scheme; }public void run() { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1")); } catch (IOException e) { e.printStackTrace(); System.exit(1); }while (!stopped) { Socket socket = null; try {socket = serverSocket.accept(); } catch (Exception e) { continue; } //处理请求 HttpProcessor processor = new HttpProcessor(this); processor.process(socket); } } public void start() { Thread thread = new Thread(this); thread.start(); } }

说明:类实现了runable接口, 其目的非常简单,后续对项目升级时使用, 比如并发请求时,使用线程的方式处理。
新增类:HttpProcessor
/** * 负责解析请求信息,调用StaticResouceProcessor跟ServletProcessor处理响应 ,原先HttpServer类拆分而成 */public class HttpProcessor {private HttpConnector connector; private HttpRequest request; private HttpResponse response; private HttpRequestLine requestLine = new HttpRequestLine(); public HttpProcessor(HttpConnector connector) { this.connector = connector; }// 响应请求 public void process(Socket socket) {SocketInputStream input = null; OutputStream output = null; try { input = new SocketInputStream(socket.getInputStream(), 2048); output = socket.getOutputStream(); request = new HttpRequest(input); response = new HttpResponse(output); response.setRequest(request); response.setHeader("Server", "Pyrmont Servlet Container"); parseRequest(input, output); parseHeaders(input); // 响应请求socket.close(); } catch (Exception e) { e.printStackTrace(); } } private void parseRequest(SocketInputStream input)throws IOException { //读取请求数据,封装成reauestLine对象 input.readRequestLine(requestLine); String method = new String(requestLine.method, 0, requestLine.methodEnd); String protocol = new String(requestLine.protocol, 0, requestLine.protocolEnd); if (method.length() < 1 || requestLine.uriEnd < 1) { throw new RuntimeException("解析请求出错"); } request.setMethod(method); request.setProtocol(protocol); //对uri进行拆分,分uri + 查询参数 String uri = null; int question = requestLine.indexOf("?"); if (question >= 0) { request.setQueryString(new String(requestLine.uri, question + 1, requestLine.uriEnd - question - 1)); uri = new String(requestLine.uri, 0, question); } else { request.setQueryString(null); uri = new String(requestLine.uri, 0, requestLine.uriEnd); }request.setRequestURI(uri); System.out.println("method:" + request.getMethod()); System.out.println("protocol:" + request.getProtocol()); System.out.println("uri:" + request.getRequestURI()); System.out.println("queryString:" + request.getQueryString()); }/** * 解析请求头信息 * * @param input */ private void parseHeaders(SocketInputStream input) throws IOException { while (true) { HttpHeader header = new HttpHeader(); input.readHeader(header); if (header.nameEnd == 0) { if (header.valueEnd == 0) { return; } else { throw new RuntimeException("解析请求头报错"); } }String name = new String(header.name, 0, header.nameEnd); String value = https://www.it610.com/article/new String(header.value, 0, header.valueEnd); request.addHeader(name, value); if (name.equals("content-length")) { int n = -1; try { n = Integer.parseInt(value); } catch (Exception e) { throw new RuntimeException("解析请求头报错"); } request.setContentLength(n); } else if (name.equals("content-type")) { request.setContentType(value); } } } }

【大飞带你深入理解Tomcat(六)】新增类:Boostrap
用于启动tomcat
public final class Bootstrap { public static void main(String[] args) { // 服务器启动 HttpConnector connector = new HttpConnector(); connector.start(); } }

大飞带你深入理解Tomcat(六)
文章图片
WechatIMG9.jpeg

    推荐阅读