我手写的简易tomcat

前述

  本身手写的简易的tomcat,实现了tomcat的基本响应功能,项目代码已经上传到个人Github,刚刚开始学习这里,当前还存在不少问题html

项目简述及代码

  当咱们的Web运行的时候,从浏览器发出的请求,必然首先到达tomcat中,以后由tomcat进行处理,由此要考虑tomcat要进行哪些处理,首先即是提供Socket服务,以后对于请求进行分发,把请求和产生的响应封装成request和responsejava

  (1)提供Socket服务git

  (2)封装请求/响应对象github

  (3)将不一样的请求映射到具体的Servlet处理浏览器

处理请求

  咱们首先考虑的,是客户端发送来请求时,咱们应该怎么去识别它,这里涉及到的就是HTTP请求协议的部分,我直接那Github页面的HTTP请求协议作例子来讲,以下图tomcat

  咱们能够看到,在Request头的首行,由 GET  /jyroy  HTTP/1.1 三部分构成,而这三部分分别的含义是 请求方法  请求路径  请求协议及其对应版本号服务器

  咱们在拿到Resquest请求以后根据上面的分析,拿到相应的信息就能够进行后续的处理了。app

 

 1 package myTomcat;
 2 
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 
 6 /**
 7  * @author jyroy
 8  *
 9  */
10 public class MyRequest {
11     
12     //请求路径
13     private String url;
14     //请求方法
15     private String method;
16     
17     //读取输入字节流,封装成字符串格式的请求内容
18     public MyRequest(InputStream inputStream) throws IOException{
19         String httpRequest = "";
20         
21         byte[] httpRequestBytes = new byte[1024];
22         
23         int length = 0;
24         
25         if((length = inputStream.read(httpRequestBytes)) > 0) {
26             httpRequest = new String(httpRequestBytes, 0, length);
27         }
28         //HTTP请求协议:首行的内容依次为:请求方法、请求路径以及请求协议及其对应版本号
29         //                           GET    /index        HTTP/1.1
30         String httpHead = httpRequest.split("\n")[0];    //取出HTTP请求协议的首行
31         System.out.println(httpHead);
32         method = httpHead.split("\\s")[0];     //按照空格进行分割,第一个是请求的方法
33         url = httpHead.split("\\s")[1];      //按照空格进行分割,第二个是请求的路径
34         System.out.println(this.toString());
35     }
36 
37     public String getUrl() {
38         return url;
39     }
40 
41     public void setUrl(String url) {
42         this.url = url;
43     }
44 
45     public String getMethod() {
46         return method;
47     }
48 
49     public void setMethod(String method) {
50         this.method = method;
51     }
52 
53     @Override
54     public String toString() {
55         return "MyRequest [url=" + url + ", method=" + method + "]";
56     }
57     
58     
59 }

 

处理响应

  考虑完接受请求以后,咱们再来考虑一下怎么来作出咱们的响应,浏览器才能识别,这里要涉及到的就是HTTP响应报文的内容,个人思路是,利用字符串拼接出Response报文,再将String转换为字节流就能够了。socket

  咱们也是来看一下Github的Response报文的格式,以下图ide

  这么多的响应头,其实不是所有须要的,咱们只须要写入一些基本的必须响应头信息,例如 请求协议及其对应版本号  响应号 响应状态 和 Cotent-type 等,以下

  最后只要转化字节流就能够

  

 1 package myTomcat;
 2 
 3 import java.io.IOException;
 4 import java.io.OutputStream;
 5 
 6 public class MyResponse {
 7     private OutputStream outputStream;
 8     
 9     public MyResponse(OutputStream outputStream) {
10         this.outputStream = outputStream;
11     }
12     
13     //将文本转换为字节流
14     public void write(String content) throws IOException{
15         StringBuffer httpResponse = new StringBuffer();
16         httpResponse.append("HTTP/1.1 200 OK\n")      //按照HTTP响应报文的格式写入
17                     .append("Content-Type:text/html\n")
18                     .append("\r\n")
19                     .append("<html><head><link rel=\"icon\" href=\"data:;base64,=\"></head><body>")
20                     .append(content)          //将页面内容写入
21                     .append("</body></html>");
22         outputStream.write(httpResponse.toString().getBytes());      //将文本转为字节流
23         outputStream.close();
24     }
25     
26 }

 

Servlet请求处理基类

  当咱们的请求和响应都已经准备好以后,接下来考虑servlet请求处理的部分,tomcat自己是一种知足servlet规范的容器,咱们须要识别接收到的请求以后并作出响应,就涉及到了 doGet  doPost  service 三个方法 

 1 package myTomcat;
 2 
 3 /**
 4  * @author jyroy
 5  * 提供API:doGet doPost service 方法
 6  */
 7 public abstract class MyServlet {
 8     
 9     public void service(MyRequest myRequest, MyResponse myResponse) {
10         if(myRequest.getMethod().equalsIgnoreCase("POST")) {
11             doPost(myRequest, myResponse);
12         }else if(myRequest.getMethod().equalsIgnoreCase("GET")) {
13             doGet(myRequest, myResponse);
14         }
15     }
16     
17     public void doGet(MyRequest myRequest, MyResponse myResponse) {
18         
19     }
20     
21     public void doPost(MyRequest myRequest, MyResponse myResponse) {
22         
23     }
24     
25 }

 

 

 Servlet配置

  考虑完上述问题以后,下一步须要的是分配url给哪个servlet来处理,首先须要的就是一个反应映射关系的类

  

 1 package myTomcat;
 2 
 3 public class ServletMapping {
 4     private String servletName;
 5     private String url;
 6     private String clazz;
 7     
 8     public ServletMapping(String servletName, String url, String clazz) {
 9         super();
10         this.servletName = servletName;
11         this.url = url;
12         this.clazz = clazz;
13     }
14 
15     public String getServletName() {
16         return servletName;
17     }
18 
19     public void setServeletName(String servletName) {
20         this.servletName = servletName;
21     }
22 
23     public String getUrl() {
24         return url;
25     }
26 
27     public void setUrl(String url) {
28         this.url = url;
29     }
30 
31     public String getClazz() {
32         return clazz;
33     }
34 
35     public void setClazz(String clazz) {
36         this.clazz = clazz;
37     }
38 }

 

  以及相关配置文件

 1 package myTomcat;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 /**
 7  * @author jyroy
 8  * 
 9  */
10 public class ServletMappingConfig {
11     public static List<ServletMapping> servletMappingList = new ArrayList<>();
12     
13      static {
14         servletMappingList.add(new ServletMapping("index", "/index", "myTomcat.test.IndexServlet"));
15         servletMappingList.add(new ServletMapping("myblog", "/myblog", "myTomcat.test.MyBlog"));
16      }
17 }

 

 核心类

  最终,咱们准备好基类后,须要的就是实现开始提到的整个处理流程

 

  (1)提供Socket服务

 

  (2)封装请求/响应对象

 

  (3)将不一样的请求映射到具体的Servlet处理

 

  这里重点说的是,要利用 ServerSocket 经过服务器上的端口通讯 以及 accpt方法一直等待客户端的请求

  具体逻辑在代码中注释

 1 package myTomcat;
 2 
 3 import java.io.InputStream;
 4 import java.io.OutputStream;
 5 import java.net.ServerSocket;
 6 import java.util.HashMap;
 7 import java.util.Map;
 8 import java.net.Socket;
 9 
10 /**
11  * @author jyroy
12  * Tomcat的处理流程:把URL对应处理的Servlet关系造成,解析HTTP协议,封装请求/响应对象,
13  * 利用反射实例化具体的Servlet进行处理便可。
14  */
15 public class MyTomcat {
16     private Integer port = 8080;     //定义8080端口
17     
18     private Map<String, String> urlServletMapping = new HashMap<>();    //存储url和对应的类
19 
20     public MyTomcat(Integer port) {
21         super();
22         this.port = port;
23     }
24     
25     @SuppressWarnings("resource")
26     public void start() {
27         initServletMapping();
28         
29             try {
30                 ServerSocket serverSocket = null;     //实例化一个 ServerSocket 对象,表示经过服务器上的端口通讯
31                 serverSocket = new ServerSocket(port);   
32                 System.out.println("MyTomcat is starting...");
33                 while(true) {
34                     Socket socket = serverSocket.accept();     //服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端链接到服务器上给定的端口 
35                     InputStream inputStream = socket.getInputStream();
36                     OutputStream outputStream = socket.getOutputStream();
37                     
38                     MyRequest myRequest = new MyRequest(inputStream);
39                     MyResponse myResponse = new MyResponse (outputStream);
40                     
41                     dispatch(myRequest, myResponse);
42             
43                     socket.close();                
44                 }
45             }catch(Exception e) {
46                 e.printStackTrace();
47             }
48         
49 //        }finally {
50 //            if(serverSocket != null) {
51 //                try {
52 //                    serverSocket.close();
53 //                }catch(Exception e){
54 //                    e.printStackTrace();
55 //                }
56 //            }
57 //        }
58     }
59     
60     //初始化映射
61     public void initServletMapping() {
62         for(ServletMapping servletMapping : ServletMappingConfig.servletMappingList) {
63             urlServletMapping.put(servletMapping.getUrl(), servletMapping.getClazz());
64         }
65     }
66     
67     //分发请求
68     @SuppressWarnings("unchecked")
69     public void dispatch(MyRequest myRequest, MyResponse myResponse) {
70         String clazz = urlServletMapping.get(myRequest.getUrl());
71         
72         try {
73             Class<MyServlet> myServletClass = (Class<MyServlet>)Class.forName(clazz); 
74             MyServlet myservlet = myServletClass.newInstance();
75             myservlet.service(myRequest, myResponse);
76         }catch(ClassNotFoundException e) {
77             e.printStackTrace();
78         }catch(InstantiationException e) {
79             e.printStackTrace();
80         }catch(IllegalAccessException e) {
81             e.printStackTrace();
82         }
83     }
84     
85     public static void main(String[] args) {
86         MyTomcat myTomcat = new MyTomcat(8080);
87         myTomcat.start();
88     }
89     
90 }

 

测试类

 1 package myTomcat.test;
 2 
 3 import java.io.IOException;
 4 
 5 import myTomcat.MyRequest;
 6 import myTomcat.MyResponse;
 7 import myTomcat.MyServlet;
 8 
 9 public class IndexServlet extends MyServlet {
10     @Override
11     public void doGet(MyRequest myRequest, MyResponse myResponse) {
12         try {
13             myResponse.write("Hello, myTomcat");
14         } catch (IOException e) {
15             e.printStackTrace();
16         }
17     }
18     
19     @Override
20     public void doPost(MyRequest myRequest, MyResponse myResponse) {
21         try {
22             myResponse.write("Hello, myTomcat");
23         } catch (IOException e) {
24             e.printStackTrace();
25         }
26     }
27 }
 1 package myTomcat.test;
 2 
 3 import java.io.IOException;
 4 
 5 import myTomcat.MyRequest;
 6 import myTomcat.MyResponse;
 7 import myTomcat.MyServlet;
 8 
 9 public class MyBlog extends MyServlet {
10     @Override
11     public void doGet(MyRequest myRequest, MyResponse myResponse) {
12         try {
13             myResponse.write("Hello, this is my blog");
14         } catch (IOException e) {
15             e.printStackTrace();
16         }
17     }
18     @Override
19     public void doPost(MyRequest myRequest, MyResponse myResponse) {
20         try {
21             myResponse.write("Hello, this is my blog");
22         } catch (IOException e) {
23             e.printStackTrace();
24         }
25     }
26 }

 

运行结果

相关文章
相关标签/搜索