上接 一个简单的 web 服务器 - 支持静态资源请求 https://www.cnblogs.com/fudashi233/p/10854232.html , 这个服务器可以处理静态资源的请求, 那么如何处理 Servlet 请求的呢?
判断是否是 Servlet 请求
首先 Web 服务器需要判断当前请求是否是 Servlet 请求.
像 Tomcat, 通过解析 HTTP 报文拿到请求 url 后, 就可以根据 Web.xml 来查找是否有匹配的 Servlet, 如果有匹配则认定为是一个有效的 Servlet 请求, 然后将 request,response 传给对应的 servlet 的 service() 方法.
这里既然要实现一个简单的 Web 服务器, 就怎么简单怎么来. 认定以 "/servlet" 为前缀的 url 为 Servlet 请求, 比如 http://localhost:8080/servlet/cn.edu.jxau.tomcat.PrimitiveServlet, 则是一个请求 cn.edu.jxau.tomcat.PrimitiveServlet 的 Servlet 请求. 判定逻辑如下
- // HttpServer 类的 service() 方法, 是整个服务器的入口
- while (true) {
- try (Socket socket = serverSocket.accept()) {
- System.out.println("客户端建立连接:" + socket);
- Request request = new Request(socket.getInputStream());
- if (Objects.isNull(request.getUri())) {
- continue;
- }
- if (isShutdownComment(request)) { // 如果是 shutdown 命令, 则关闭服务器
- break;
- }
- Response response = new Response(request, socket.getOutputStream());
- if (request.getUri().startsWith("/servlet/")) { // 请求 Servlet 资源
- new ServletProcessor().process(request, response);
- } else { // 请求静态资源
- response.sendStaticResource();
- // 书上使用了 StaticResourceProcessor new StaticResourceProcessor().process(request,response);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
加载 Servlet
如果确实是 Servlet 请求, 下一步就是实例化 Servlet 并调用 service() 方法.
首先需要知道请求是哪个 Servlet: 根据 url 拿到 Servlet 的名称
然后需要调用 Servlet 的 service() 方法: 使用 ClassLoader 加载对应的 Servlet 字节码, 然后实例化 Servlet, 调用 service() 方法, 传入 request,response.
- // ServletProcessor 类的 process() 方法, 用于处理 Servlet 请求
- public void process(Request request, Response response) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException {
- String uri = request.getUri();
- String servletName = uri.substring(uri.lastIndexOf("/") + 1);
- File file = new File(Constants.WEB_ROOT);
- String urlStr = new URL("file", null, file.getCanonicalPath() + File.separator).toString(); // 使用 File 协议
- URL[] urlArr = new URL[1];
- urlArr[0] = new URL(urlStr);
- System.out.println(Arrays.toString(urlArr));
- URLClassLoader loader = new URLClassLoader(urlArr);
- Class clazz = loader.loadClass(servletName); // 根据 Servlet 的全路径名加载 Servlet 字节码
- Servlet servlet = (Servlet) clazz.newInstance(); // 实例化 Servlet
- servlet.service(request, response); // 调用 Servlet.service()
- }
PrimitiveServlet 的实现如下, 实现了 Servlet 接口, service() 方法的实现是重点.
- public class PrimitiveServlet implements Servlet {
- public void init(ServletConfig config) throws ServletException {
- System.out.println("-----init");
- }
- public void service(ServletRequest request, ServletResponse response)
- throws ServletException, IOException {
- PrintWriter out = response.getWriter();
- out.println("HTTP/1.1 200 Status OK\r\n");
- out.println("Content-Type: text/html\r\n");
- out.println("Content-Length: 36\r\n");
- out.println("\r\n");
- out.println("<h1>Status OK</h1>");
- out.print("<h1>Status OK</h1>");
- }
- public void destroy() {
- System.out.println("-------destroy");
- }
- public String getServletInfo() {
- return null;
- }
- public ServletConfig getServletConfig() {
- return null;
- }
- }
参考
1.《How Tomcat Works》 - Budi Kurniawan
来源: http://www.bubuko.com/infodetail-3087889.html