大飞带你深入理解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 = 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);
            }
        }
    }
}

新增类:Boostrap
用于启动tomcat

public final class Bootstrap {
    public static void main(String[] args) {
        // 服务器启动
        HttpConnector connector = new HttpConnector();
        connector.start();
    }
}
大飞带你深入理解Tomcat(六)_第1张图片
WechatIMG9.jpeg

你可能感兴趣的:(大飞带你深入理解Tomcat(六))