手写简单的tomcat

首先,Tomcat是一个软件,所有的项目都能在Tomcat上加载运行,Tomcat最核心的就是Servlet集合,本身就是HashMap。Tomcat需要支持Servlet,所以有servlet底层的资源:HttpServlet抽象类、HttpRequest和HttpResponse,否则我们无法新建Servlet。

http协议:客户端和用户端进行请求和响应的过程:

这样我们就可以在webapps写项目了,一个项目有两大资源:servlet资源和静态资源,servlet本身是java类,我们让它调用doGet和doPost方法,必须继承HttpServlet,同时也需要@WebServlet注解,那么在Tomcat中就必须要有@WebServlet注解的实现,如果没有@WebServlet,我们就无法拿到相应的注解。这样我们就能成功搭建起Servlet资源。

当Http请求打过来之后,先打到socket上,处理Http请求,其本身就是连接器,从请求上能获取到请求路径和请求方法。先获取到请求路径,判断servlet容器中是否含有相同路径,如果有,再获取请求方法,判断是doGet还是doPost。


简易版tomcat的核心原理

真正的Tomcat很复杂,但它的最核心功能可以简化为:

  1. 监听HTTP请求(Socket 绑定 8080 端口)
  2. 解析HTTP请求(读取请求头、请求体)
  3. 找到对应的Servlet处理请求 (反射调用 service() 方法)
  4. 返回HTTP响应(写回响应头和HTML)

手写tomcat

首先,定义Servlet接口

java 复制代码
public interface servlet {
    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException;
}

其次,定义request和response

java 复制代码
public class HttpServletRequest {
    private String method;
    private String url;
    //............

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}


public class HttpServletResponse {

    //输出流
    private OutputStream outputStream;
    public HttpServletResponse(OutputStream outputStream){
        this.outputStream = outputStream;
    }

    /**
     * 返回动态资源
     * @param context
     */
    public void write(String context) throws IOException {
        //System.out.println(context);
        outputStream.write(context.getBytes());
    }

    /**
     * 返回静态资源
     */
    public void writeHtml(String path) throws Exception {
        String resourcesPath = FileUtil.getResoucePath(path);
        File file = new File(resourcesPath);
        if(file.exists()){
            //静态文件存在
            System.out.println("静态文件存在");
            FileUtil.writeFile(file,outputStream);
        }else {
            System.out.println("静态文件不存在");
            write(ResponseUtil.getResponseHeader404());
        }
    }

}

然后,实现一个Httpserver

java 复制代码
public class MyTomcat {

    static HashMap<String, HttpServlet> routes = TomcatRoute.routes; //tomcat路由\


    /**
     * 分发器
     */
    public  void dispatch(HttpServletRequest request ,HttpServletResponse response) throws IOException {
        System.out.println("URL: " + request.getUrl());
        HttpServlet servlet = routes.get(request.getUrl());  //
        if(servlet!=null){ //说明请求的就是我们的servlet
            System.out.println("找到匹配的Servlet: " + servlet.getClass().getName());
            servlet.service(request,response);
        }
    }

    /**
     * socket 启动
     * @throws IOException
     */
    public  void start() throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);  //1.指定监听的端口号
        //2.对端口进行监听
        while (true){
            Socket socket = serverSocket.accept();//阻塞监听
            //3.打开输入流,解析客户端发来的内容
            InputStream inputStream = socket.getInputStream(); //输入流
            HttpServletRequest request = new HttpServletRequest();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));  //将字节流转换成字符流
            String str = reader.readLine();
            //分割
            request.setMethod(str.split("\\s")[0]);
            request.setUrl(str.split("\\s")[1]);

            //4.打开输出流
            OutputStream outputStream = socket.getOutputStream();
            HttpServletResponse response = new HttpServletResponse(outputStream);
            //分发器
            dispatch(request,response);
            socket.close();//socket在这里关闭
        }

    }

    //socket
    public static void main(String[] args) throws IOException {
        MyTomcat myTomcat = new MyTomcat();
        myTomcat.start();
    }
}

然后,自定义一个Servlet

java 复制代码
@CYServlet(url = "/myServlet")
public class MyFirstServlet extends HttpServlet {
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        super.doPost(request, response);
    }

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("Hello World!");
        System.out.println("Servlet实例: " + this);
        response.write(ResponseUtil.getResponseHeader200("hello world  hhhhh"));
    }
}

最后,启动服务并测试

java 复制代码
public static void main(String[] args) throws IOException {
        MyTomcat myTomcat = new MyTomcat();
        myTomcat.start();
    }

访问浏览器localhost:8080会得到:

相关推荐
小猪咪piggy33 分钟前
【JavaEE】(1) 计算机如何工作
java
smileNicky37 分钟前
SpringBoot系列之OpenAI API 创建智能博客评论助手
java·spring boot·后端
弥鸿1 小时前
MinIO的安装和使用
java·spring boot·java-ee·springcloud·javaee
丿BAIKAL巛2 小时前
如何使用Java生成pdf报告
java·pdf
hy.z_7772 小时前
【数据结构】 栈和队列
java·数据结构
栗子~~3 小时前
idea 安装飞算-javaAI 插件使用
java·ide·intellij-idea
zy happy4 小时前
黑马点评前端Nginx启动失败问题解决记录
java·运维·前端·spring boot·nginx·spring
lxyker4 小时前
MongoDB大数据量的优化——mongoTemplate.stream()方法使用
java·数据库·mongodb·性能优化·数据库调优
煤灰2424 小时前
简单用c++的类实现的string
java·开发语言·c++