前面第二章讲的是简单的servlet容器,其中HttpServer类负责等待Http请求,然后构建解析request,response,之后再通过ClassLoader调用servlet的service方法或者说直接调用静态资源。
到了第三章,就将上一章中的HttpServer类中的等待接受Http请求与解析request,response两大职责拆分了开来,前者成为了HttpConnector,负责构建serverSocket接受请求,后者成为了HttpProcessor,负责解析request与response。
下面这张UML图描述了这些类的关系:
下面说一下程序执行的流程:
HttpConnector connector = new HttpConnector();
connector.start();
首先BootStrap类启动HttpConnector.
public void run() {
ServerSocket serverSocket = null;
int port = 8080;
try {
serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
}
...
while (!stopped) {
// Accept the next incoming connection from the server socket
Socket socket = null;
try {
socket = serverSocket.accept();
}
catch (Exception e) {
continue;
}
// Hand this socket off to an HttpProcessor
HttpProcessor processor = new HttpProcessor(this);
processor.process(socket);
}
}
然后构建serverSocket ,进入循环之中等待Htttp请求的到来,获取socket之后,调用HttpProcessor的process方法。
public void process(Socket socket) {
SocketInputStream input = null;
OutputStream output = null;
try {
input = new SocketInputStream(socket.getInputStream(), 2048);
output = socket.getOutputStream();
// create HttpRequest object and parse
request = new HttpRequest(input);
// create HttpResponse object
response = new HttpResponse(output);
response.setRequest(request);
response.setHeader("Server", "Pyrmont Servlet Container");
parseRequest(input, output);
parseHeaders(input);
// check if this is a request for a servlet or a static resource
// a request for a servlet begins with "/servlet/"
if (request.getRequestURI().startsWith("/servlet/")) {
ServletProcessor processor = new ServletProcessor();
processor.process(request, response);
} else {
StaticResourceProcessor processor = new StaticResourceProcessor();
processor.process(request, response);
}
// Close the socket
socket.close();
// no shutdown for this application
} catch (Exception e) {
e.printStackTrace();
}
}
到了这个方法之后,就创建HttpRequest,HttpRespnse实例,解析请求,解析头部最后再根据uri决定是调用静态资源的process方法,还是调用servlet的service方法。
其实Http请求解析是相当复杂的任务,这里总结一下书上的具体流程:
- 获取套接字输入流
- 解析请求行(一般是为了获取uri)
- 解析头部
- 解析cookies
- 获取参数