手写tomcat:根本功能实现(3)

打印 上一主题 下一主题

主题 1966|帖子 1966|积分 5898

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
 TomcatRoute类

TomcatRoute类是Servlet容器,是Tomcat中最核心的部分,其自己是一个HashMap,其功能为:将路径和对象写入Servlet容器中。
  1. package com.qcby.config;
  2. import com.qcby.Util.SearchClassUtil;
  3. import com.qcby.servlet.Httpservlet;
  4. import com.qcby.zj.YbyServlet;
  5. import java.util.HashMap;
  6. import java.util.List;
  7. import java.util.List;
  8. import java.util.Map;
  9. public class TomcatRoute {
  10.     public static HashMap<String, Httpservlet> Route = new HashMap<>();
  11.         static {
  12.             List<String> classesPath = SearchClassUtil.searchClass();
  13.             for (String path : classesPath) {
  14.                 try {
  15.                     //加载类
  16.                     Class clazz = Class.forName(path);
  17.                     //获取注解
  18.                     YbyServlet webServlet = (YbyServlet) clazz.getDeclaredAnnotation(YbyServlet.class);
  19. //                对象
  20.                     Object servlet = clazz.getDeclaredConstructor().newInstance();
  21.                     Route.put(webServlet.url(), (Httpservlet) servlet);
  22. //                Httpservlet servlet = (Httpservlet) clazz.newInstance();
  23. //                servletMap.put(webServlet.url(),servlet);
  24.                     System.out.println(Route);
  25.                 } catch (Exception e) {
  26.                     e.printStackTrace();
  27.                 }
  28.             }
  29.         }
  30. }
复制代码
 静态代码块 

1. 确保初始化时机

静态代码块在类加载时自动执行,且仅执行一次。这确保了路由表在程序启动时就被初始化,后续无需手动调用初始化方法。
对比其他初始化方式



  • 构造函数:每次创建对象时都会执行,而路由表只需初始化一次。
  • 普通静态方法:需要手动调用,可能被忘记或重复调用。
  • 静态代码块:自动触发,保证全局唯一性。
2. 全局唯一性

静态代码块属于类,而非某个实例。无论创建多少个TomcatRoute对象,路由表只会初始化一次。
功能



  • 自动扫描:通过 SearchClassUtil.searchClass() 扫描项目中的所有类。
  • 注解辨认:使用 @YbyServlet 注解标记需要注册的 Servlet。
  • 路由映射:将注解中的 url() 值作为路径,对应的 Servlet 实例作为值,存入静态的 Route 映射表。
  • 类加载时初始化:利用静态代码块在类加载时执行初始化逻辑,确保路由表在程序启动时就已准备好。
public static HashMap<String, Httpservlet> Route = new HashMap<>();

1. 多态性的应用

Httpservlet是所有具体 Servlet 的抽象父类(或接口),通过父类范例引用子类实例,可以实现统一调用
2. 解耦路由逻辑与具体实现

路由系统只需关注哀求路径与处置惩罚逻辑的映射关系,而无需关心具体 Servlet 的实现细节。
3. 统一接口界说

Httpservlet通常界说了处置惩罚哀求的标准方法(如service()、doGet()、doPost()),所有子类必须实现这些方法。
4. 符合 Servlet 规范

在标准 Java Web 开辟中,所有 Servlet 都必须实现javax.servlet.Servlet接口(或继续HttpServlet)。这种设计模仿了标准 Servlet 容器的工作原理。
MyTomcat

  1. package com.qcby;
  2. //tomcat主启动类
  3. import com.qcby.config.TomcatRoute;
  4. import com.qcby.servlet.Httpservlet;
  5. import com.qcby.Request.HttpServletRequest;
  6. import com.qcby.Response.HttpServletResponse;
  7. import java.io.InputStream;
  8. import java.io.OutputStream;
  9. import java.net.ServerSocket;
  10. import java.net.Socket;
  11. import java.util.HashMap;
  12. public class Mytomcat {
  13.     static HashMap<String,Httpservlet> routes= TomcatRoute.Route;
  14.     static  HttpServletRequest request=new HttpServletRequest();
  15.    static  HttpServletResponse response=new HttpServletResponse();
  16.     public  static void dispatch(){
  17.         Httpservlet servlet=routes.get(request.getPath());
  18.         if(servlet!=null){
  19.             servlet.service(request,response);
  20.         }
  21.     }
  22.     public static void main(String[] args) {
  23.         try {
  24.             System.out.append("服务器启动......");
  25. //                                1.定义ServerSocket对象进行服务器的端口注册
  26.             ServerSocket serverSocket = new ServerSocket(8080);
  27.             while (true) {
  28. //                                2.监听客户端的socket链接程序
  29.                 Socket socket = serverSocket.accept();//阻塞监听
  30. //                                3.从socket对象当中获得一个字节流对象
  31.                 InputStream iStream = socket.getInputStream();
  32. //                                打印输出
  33.                 int len = 0;
  34.                 int ReviceLen = 0;
  35. //                        计算机网络数据是以8bit为一个单元进行发送,我们接收到发送方发生的byte数据
  36. //                                将其转化为utf-8格式输出
  37.                 byte[] recvBuf = new byte[1024];
  38.                 while ((ReviceLen = iStream.read(recvBuf)) != -1) {
  39.                     String count=new String(recvBuf,0,ReviceLen,"UTF-8");
  40.                     String method=count.split(" ")[0];
  41.                     String url=count.split(" ")[1];
  42.                     request.setMethod(method);
  43.                     request.setPath(url);
  44.                 }
  45.                 dispatch();
  46.             }
  47.             } catch(Exception e){
  48.                 // TODO: handle exception
  49.             }
  50.         }
  51. }
复制代码
1. 团体架构

这个浅易服务器包含三个核心组件:


  • Mytomcat:主服务器类,负责接收哀求和分发。
  • TomcatRoute:路由配置类,通过静态代码块扫描并注册所有 Servlet。
  • Httpservlet:抽象 Servlet 基类,界说哀求处置惩罚接口。
2. 核心成员变量 

  1. static HashMap<String,Httpservlet> routes = TomcatRoute.Route;
  2. static HttpServletRequest request = new HttpServletRequest();
  3. static HttpServletResponse response = new HttpServletResponse();
复制代码


  • routes:从 TomcatRoute 获取的路由表,存储 URL → Servlet 的映射关系。
  • request 和 response:静态全局对象,用于存储当前哀求和相应信息。
 3. 哀求分发逻辑

  1. public static void dispatch() {
  2.     Httpservlet servlet = routes.get(request.getPath());
  3.     if (servlet != null) {
  4.         servlet.service(request, response);
  5.     }
  6. }
复制代码


  • 根据 request.getPath() 从路由表中查找对应的 Servlet。
  • 调用 Servlet 的 service() 方法处置惩罚哀求(多态调用)。
4. 主服务器逻辑

  1. public static void main(String[] args) {
  2.     try {
  3.         System.out.println("服务器启动......");
  4.         ServerSocket serverSocket = new ServerSocket(8080);
  5.         
  6.         while (true) {
  7.             // 1. 监听客户端连接(阻塞)
  8.             Socket socket = serverSocket.accept();
  9.             InputStream iStream = socket.getInputStream();
  10.             
  11.             // 2. 解析HTTP请求
  12.             byte[] recvBuf = new byte[1024];
  13.             int ReviceLen = iStream.read(recvBuf);
  14.             String count = new String(recvBuf, 0, ReviceLen, "UTF-8");
  15.             String method = count.split(" ")[0];
  16.             String url = count.split(" ")[1];
  17.             
  18.             // 3. 设置请求信息
  19.             request.setMethod(method);
  20.             request.setPath(url);
  21.             
  22.             // 4. 分发请求
  23.             dispatch();
  24.         }
  25.     } catch (Exception e) {
  26.         e.printStackTrace();
  27.     }
  28. }
复制代码
关键步调


  • 创建服务器套接字:监听 8080 端口。
  • 接收客户端连接:通过 serverSocket.accept() 壅闭等待哀求。
  • 解析 HTTP 哀求

    • 读取哀求头的第一行(格式:GET /path HTTP/1.1)。
    • 提取 HTTP 方法(如 GET)和哀求路径(如 /login)。

  • 设置哀求对象:将解析结果存入静态 request 对象。
  • 分发哀求:调用 dispatch() 方法查找并执行对应的 Servlet。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

傲渊山岳

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表