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

TomcatRoute类

TomcatRoute类是Servlet容器,是Tomcat中最核心的部分,其本身是一个HashMap,其功能为:将路径和对象写入Servlet容器中。

java 复制代码
package com.qcby.config;

import com.qcby.Util.SearchClassUtil;
import com.qcby.servlet.Httpservlet;
import com.qcby.zj.YbyServlet;

import java.util.HashMap;
import java.util.List;

import java.util.List;
import java.util.Map;

public class TomcatRoute {
    public static HashMap<String, Httpservlet> Route = new HashMap<>();


        static {
            List<String> classesPath = SearchClassUtil.searchClass();
            for (String path : classesPath) {
                try {
                    //加载类
                    Class clazz = Class.forName(path);
                    //获取注解
                    YbyServlet webServlet = (YbyServlet) clazz.getDeclaredAnnotation(YbyServlet.class);
//                对象
                    Object servlet = clazz.getDeclaredConstructor().newInstance();
                    Route.put(webServlet.url(), (Httpservlet) servlet);
//                Httpservlet servlet = (Httpservlet) clazz.newInstance();
//                servletMap.put(webServlet.url(),servlet);
                    System.out.println(Route);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }


}

静态代码块

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

java 复制代码
package com.qcby;
//tomcat主启动类
import com.qcby.config.TomcatRoute;
import com.qcby.servlet.Httpservlet;
import com.qcby.Request.HttpServletRequest;
import com.qcby.Response.HttpServletResponse;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

public class Mytomcat {


    static HashMap<String,Httpservlet> routes= TomcatRoute.Route;
    static  HttpServletRequest request=new HttpServletRequest();
   static  HttpServletResponse response=new HttpServletResponse();
    public  static void dispatch(){
        Httpservlet servlet=routes.get(request.getPath());
        if(servlet!=null){
            servlet.service(request,response);
        }
    }

    public static void main(String[] args) {
        try {

            System.out.append("服务器启动......");
//				1.定义ServerSocket对象进行服务器的端口注册
            ServerSocket serverSocket = new ServerSocket(8080);
            while (true) {
//				2.监听客户端的socket链接程序
                Socket socket = serverSocket.accept();//阻塞监听
//				3.从socket对象当中获得一个字节流对象
                InputStream iStream = socket.getInputStream();

//				打印输出
                int len = 0;
                int ReviceLen = 0;
//			计算机网络数据是以8bit为一个单元进行发送,我们接收到发送方发生的byte数据
//				将其转化为utf-8格式输出
                byte[] recvBuf = new byte[1024];
                while ((ReviceLen = iStream.read(recvBuf)) != -1) {
                    String count=new String(recvBuf,0,ReviceLen,"UTF-8");
                    String method=count.split(" ")[0];
                    String url=count.split(" ")[1];
                    request.setMethod(method);
                    request.setPath(url);

                }
                dispatch();
            }
            } catch(Exception e){
                // TODO: handle exception
            }
        }


}

1. 整体架构

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

  • Mytomcat:主服务器类,负责接收请求和分发。
  • TomcatRoute:路由配置类,通过静态代码块扫描并注册所有 Servlet。
  • Httpservlet:抽象 Servlet 基类,定义请求处理接口。

2. 核心成员变量

java 复制代码
static HashMap<String,Httpservlet> routes = TomcatRoute.Route;
static HttpServletRequest request = new HttpServletRequest();
static HttpServletResponse response = new HttpServletResponse();
  • routes:从 TomcatRoute 获取的路由表,存储 URL → Servlet 的映射关系。
  • requestresponse:静态全局对象,用于存储当前请求和响应信息。

3. 请求分发逻辑

java 复制代码
public static void dispatch() {
    Httpservlet servlet = routes.get(request.getPath());
    if (servlet != null) {
        servlet.service(request, response);
    }
}
  • 根据 request.getPath() 从路由表中查找对应的 Servlet。
  • 调用 Servlet 的 service() 方法处理请求(多态调用)。

4. 主服务器逻辑

java 复制代码
public static void main(String[] args) {
    try {
        System.out.println("服务器启动......");
        ServerSocket serverSocket = new ServerSocket(8080);
        
        while (true) {
            // 1. 监听客户端连接(阻塞)
            Socket socket = serverSocket.accept();
            InputStream iStream = socket.getInputStream();
            
            // 2. 解析HTTP请求
            byte[] recvBuf = new byte[1024];
            int ReviceLen = iStream.read(recvBuf);
            String count = new String(recvBuf, 0, ReviceLen, "UTF-8");
            String method = count.split(" ")[0];
            String url = count.split(" ")[1];
            
            // 3. 设置请求信息
            request.setMethod(method);
            request.setPath(url);
            
            // 4. 分发请求
            dispatch();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

关键步骤

  1. 创建服务器套接字:监听 8080 端口。
  2. 接收客户端连接 :通过 serverSocket.accept() 阻塞等待请求。
  3. 解析 HTTP 请求
    • 读取请求头的第一行(格式:GET /path HTTP/1.1)。
    • 提取 HTTP 方法(如 GET)和请求路径(如 /login)。
  4. 设置请求对象 :将解析结果存入静态 request 对象。
  5. 分发请求 :调用 dispatch() 方法查找并执行对应的 Servlet。
相关推荐
卡戎-caryon1 分钟前
【C++】15.并发支持库
java·linux·开发语言·c++·多线程
头发那是一根不剩了44 分钟前
怎么用idea分析hprof文件定位JVM内存问题
java·jvm
让代码飞~1 小时前
maven项目, idea右上角一直显示gradle的同步标识, 如何去掉
java·maven·intellij-idea
张扬飞舞1 小时前
IntelliJ IDEA克隆项目失败的解决方法
java·ide·intellij-idea
一只码代码的章鱼1 小时前
spring -MVC-02
java·spring·mvc
ziyue75751 小时前
idea启用lombok
java·intellij-idea·idea·lombok·软件
tmacfrank2 小时前
Java 原生网络编程(BIO | NIO | Reactor 模式)
java·开发语言·网络
python算法(魔法师版)2 小时前
.NET NativeAOT 指南
java·大数据·linux·jvm·.net
专注VB编程开发20年2 小时前
VB.NET关于接口实现与简化设计的分析,封装其他类
java·前端·数据库
大数据魔法师2 小时前
Redis(三) - 使用Java操作Redis详解
java·数据库·redis