【学习笔记】手写 Tomcat 八

目录

一、NIO

1. 创建 Tomcat NIO 类

2. 启动 Tomcat

3. 测试

二、解析请求信息

三、响应数据

创建响应类

修改调用的响应类

四、完整代码

五、测试

六、总结

七、获取全部用户的功能

POJO

生成 POJO

1. 在 Dao 层定义接口

2. 获取用户数据

3. 在 Service 层定义接口

4. Service 层的实现方法

5. 创建 Servlet

6. 测试

八、作业

优化NIO


一、NIO

Non-Blocking I/O,非阻塞IO。我们之前使用的是 BIO 阻塞IO

NIO 是同步非阻塞的,服务器的实现模式是一个线程处理多个连接 

关于 NIO ,可以看看这位博主写的文章 Java NIO 详解-优快云博客 

1. 创建 Tomcat NIO 类

package com.shao.net;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class TomcatNIO {

    public TomcatNIO() {

        // 1. 创建通信管道
        try {
            ServerSocketChannel ssc = ServerSocketChannel.open();

            // 2. 绑定端口
            ssc.bind(new InetSocketAddress(8080));

            // 3. 配置非阻塞通信管道
            ssc.configureBlocking(false);

            // 4. 创建一个选择器
            Selector selector = Selector.open();

            // 5. 将通信管道注册到选择器上,监听客户端连接请求的事件
            ssc.register(selector, SelectionKey.OP_ACCEPT);

            // 循环监听客户端请求并处理相应事件
            while (true) {
                System.out.println("等待连接...");
                // 6. 从 selectors 中选择并返回已就绪的通道数
                int number = selector.select();
                if (number == 0) continue;

                // 7. 这些 SelectionKey 对象代表了就绪的通道及其相应的注册事件。
                Iterator<SelectionKey> it = selector.selectedKeys().iterator();

                while (it.hasNext()) {
                    SelectionKey key = it.next();

                    // 8. 判断就绪事件类型
                    if (key.isAcceptable()) {
                        System.out.println("有客户端连接了...");

                        // 1. 接受新的客户端连接
                        SocketChannel sc = ssc.accept();

                        // 2. 设置连接的通道为非阻塞模式
                        sc.configureBlocking(false);

                        // 3. 将新连接的通道注册到选择器上,监听读事件
                        sc.register(selector, SelectionKey.OP_READ);

                        System.out.println("客户端连接成功");

                    } else if (key.isReadable()) {
                        // 读事件

                        // 1. 创建缓冲区
                        ByteBuffer buffer = ByteBuffer.allocate(1024);

                        // 2. 将 key 关联的通道 (channel) 转换为 SocketChannel 类型。转换后的 socketChannel 可用于进行网络读写操作。
                        SocketChannel socketChannel = (SocketChannel) key.channel();

                        // 3. 读取数据到缓冲区
                        int read = socketChannel.read(buffer);

                        if (read > 0) {
                            // 获取缓冲区的数据
                            byte[] array = buffer.array();

                            // 转成字符串
                            String msg = new String(array, 0, read);

                            // 将请求信息进行 URL 解码,然后使用 UTF-8 进行编码
                            String message = URLDecoder.decode(msg, "UTF-8");

                            System.out.println("客户端发送了:" + message);

                            // 清空缓冲区
                            buffer.clear();

                            // 响应数据
                            String content = "OK";
                            String HttpResponse = "HTTP/1.1 200 OK\r\n" +
                                    "Content-Type: text/html;charset=utf-8\r\n" +
                                    "Content-Length: " + content.getBytes().length + "\r\n" +
                                    "\r\n" +
                                    content;

                            // 写入到缓冲区
                            buffer.put(HttpResponse.getBytes());

                            // 将缓冲区的界限设置为当前位置,然后再把当前位置重置为0
                            buffer.flip();

                            // 响应数据到客户端
                            socketChannel.write(buffer);

                        } else if (read == -1) {

                            // 关闭通道
                            socketChannel.close();

                            // 取消 key 关联的通道在 selector 上的注册
                            key.cancel();
                        }
                    }


                    // 移除已经处理的 SelectionKey,防止下次循环再处理这个键
                    it.remove();

                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. 启动 Tomcat

在入口类启动 NIO 的 Tomcat

3. 测试

二、解析请求信息

因为请求信息和之前是一样的,所以可以使用 HttpRequest 解析类

三、响应数据

创建响应类

因为响应数据的方式不一样,所以需要创建一个 NIO 方式的响应类

package com.shao.net;

import com.shao.Servlet.BaseServlet;
import com.shao.Utils.ServletByAnnoUtil;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class HttpResponseNIO {

    /**
     * 连接的通道
     */
    private SocketChannel sc;

    /**
     * 缓冲区
     */
    private ByteBuffer buffer;

    /**
     * 解析类的对象
     */
    private HttpRequest httpRequest;

    public HttpResponseNIO(SocketChannel sc, ByteBuffer buffer, HttpRequest httpRequest) {
        this.sc = sc;
        this.buffer = buffer;
        this.httpRequest = httpRequest;
    }

    public void response(String filePath) {
        //判断请求的是否为静态文件
        if (StaticResourceHandler.isLikelyStaticResource(httpRequest.getRequestModule())) {
            // 获取静态资源一般是 GET 请求方法
            if (httpRequest.getRequestMethod().equals("GET")) {
                // 响应静态资源
                responseStaticResource(filePath);
            }
        } else {
            // 处理动态请求
            System.out.println("请求动态资源");

            // 获取 Servlet 对象,参数是请求的模块名
            BaseServlet servlet = ServletByAnnoUtil.getServletClass(httpRequest.getRequestModule());

            // 如果没有找到对应的 Servlet ,返回 404
            if (servlet == null) {
                responseStaticResource("webs/pages/not_Found404.html");
                return;
            }
            // 调用 service 方法
            servlet.service(httpRequest, this);
        }
    }

    /**
     * 响应静态资源
     */
    private void responseStaticResource(String filePath) {
        // 读取文件
        byte[] fileContents = StaticResourceHandler.getFileContents(filePath);

        // 判断文件是否存在,不存在则返回 404 的页面
        if (fileContents == null) {
            try {
                FileInputStream fis = new FileInputStream("webs/pages/not_Found404.html");

                fileContents = new byte[fis.available()];

                fis.read(fileContents);

                fis.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // 响应协议
        String protocol = httpRequest.getRequestProtocol();
        // 文件媒体类型
        String fileMimeType = StaticResourceHandler.getFileMimeType(filePath);

        // 清空缓冲区
        buffer.clear();

        // 写入数据到缓冲区
        buffer.put((protocol + " 200 OK\r\n").getBytes());
        buffer.put(("Content-Type: " + fileMimeType + "\r\n").getBytes());
        buffer.put(("Content-Length: " + fileContents.length + "\r\n").getBytes());
        buffer.put(("\r\n").getBytes());
        buffer.put(fileContents);

        // 将缓冲区的界限设置为当前位置,然后再把当前位置重置为0
        buffer.flip();

        try {
            // 响应数据到客户端
            sc.write(buffer);
            System.out.println("响应成功");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void send(byte[] content) {
        // 获取请求协议
        String protocol = httpRequest.getRequestProtocol();

        // 清空缓冲区
        buffer.clear();

        // 往缓冲区写入数据
        buffer.put((protocol + " 200 OK\r\n").getBytes());
        buffer.put(("Content-Type: text/html;charset=utf-8\r\n").getBytes());
        buffer.put(("Content-Length: " + content.length + "\r\n").getBytes());
        buffer.put("\r\n".getBytes());
        buffer.put(content);

        // 设置缓冲区的界限为当前指针的位置,然后把指针指向缓冲区的起始位置
        buffer.flip();

        try {

            // 响应数据
            sc.write(buffer);
            System.out.println("响应成功");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

修改调用的响应类

四、完整代码

package com.shao.net;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class TomcatNIO {
    public TomcatNIO() {

        // 1. 创建通信管道
        try {
            ServerSocketChannel ssc = ServerSocketChannel.open();

            // 2. 绑定端口
            ssc.bind(new InetSocketAddress(8080));

            // 3. 配置非阻塞通信管道
            ssc.configureBlocking(false);

            // 4. 创建一个选择器
            Selector selector = Selector.open();

            // 5. 将通信管道注册到选择器上,监听客户端连接请求的事件
            ssc.register(selector, SelectionKey.OP_ACCEPT);

            // 循环监听客户端请求并处理相应事件
            while (true) {
                System.out.println("等待连接...");
                // 6. 从 selectors 中选择并返回已就绪的通道数
                int number = selector.select();
                if (number == 0) continue;

                // 7. 这些 SelectionKey 对象代表了就绪的通道及其相应的注册事件。
                Iterator<SelectionKey> it = selector.selectedKeys().iterator();

                while (it.hasNext()) {
                    SelectionKey key = it.next();

                    // 8. 判断就绪事件类型
                    if (key.isAcceptable()) {
                        System.out.println("有客户端连接了...");

                        // 1. 接受新的客户端连接
                        SocketChannel sc = ssc.accept();

                        // 2. 设置连接的通道为非阻塞模式
                        sc.configureBlocking(false);

                        // 3. 将新连接的通道注册到选择器上,监听读事件
                        sc.register(selector, SelectionKey.OP_READ);

                        System.out.println("客户端连接成功");

                    } else if (key.isReadable()) {
                        // 读事件

                        // 1. 创建缓冲区
                        ByteBuffer buffer = ByteBuffer.allocate(1024);

                        // 2. 将 key 关联的通道 (channel) 转换为 SocketChannel 类型。转换后的 socketChannel 可用于进行网络读写操作。
                        SocketChannel socketChannel = (SocketChannel) key.channel();

                        // 3. 读取数据到缓冲区
                        int read = socketChannel.read(buffer);

                        if (read > 0) {
                            // 获取缓冲区的数据
                            byte[] array = buffer.array();

                            // 转成字符串
                            String msg = new String(array, 0, read);

                            // 将请求信息进行 URL 解码,然后使用 UTF-8 进行编码
                            String message = URLDecoder.decode(msg, "UTF-8");

                            // 调用 HttpRequest 类解析请求信息
                            HttpRequest httpRequest = new HttpRequest(message);

                            // 拼接请求的静态资源的路径
                            String filePath = "/webs" + httpRequest.getRequestModule();

                            // 创建响应对象
                            HttpResponseNIO httpResponseNIO = new HttpResponseNIO(socketChannel, buffer, httpRequest);

                            // 响应数据到客户端
                            httpResponseNIO.response(filePath);

                        } else if (read == -1) {

                            // 关闭通信通道
                            socketChannel.close();

                            // 取消 key 关联的通道在 selector 上的注册
                            key.cancel();
                        }
                    }

                    // 9. 移除已经处理的 SelectionKey,防止下次循环再处理这个键
                    it.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

五、测试

六、总结

七、获取全部用户的功能

POJO

因为获取的用户数据需要封装,需要一个类和数据库的字段一一对应,这就是 对象关系映射(ORM) ,这个类可以称为 POJO

生成 POJO

1. 在 Dao 层定义接口

2. 获取用户数据

public ArrayList<Users> GetAllUser() {
        Connection connection = null;
        PreparedStatement pstmt = null;
        ResultSet resultSet = null;

        ArrayList<Users> users = new ArrayList<>();

        try {
            // 3. 从连接池获取一个数据库连接
            connection = DBConnectPool.getInstance().getConnection();

            // 4. 获取可执行对象
            // 定义 SQL 语句
            String SQL = "select id, account, name, password, money from train.users";
            pstmt = connection.prepareStatement(SQL);

            // 5. 执行sql语句,获取结果集
            resultSet = pstmt.executeQuery();

            // 6. 结果处理
            while (resultSet.next()) {

                // 获取一行数据,封装到对象中
                Users user = new Users();

                user.setId(resultSet.getLong("id"));
                user.setAccount(resultSet.getString("account"));
                user.setName(resultSet.getString("name"));
                user.setPassword(resultSet.getString("password"));
                user.setMoney(resultSet.getDouble("money"));

                // 添加到集合中
                users.add(user);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBConnectPool.getInstance().releaseConnection(connection);
            DBConnectUtil.releaseSource(pstmt, resultSet);
        }
        return users;
    }

3. 在 Service 层定义接口

4. Service 层的实现方法

    public responseDTO GetAllUser() {

        // 调用 Dao 层获取数据
        ArrayList<Users> users = userDao.GetAllUser();

        return new responseDTO(200, users, "获取成功", users.size());
    }

5. 创建 Servlet

package com.shao.Servlet;

import com.alibaba.fastjson2.JSON;
import com.shao.Annotation.MyServlet;
import com.shao.Service.ServiceFactory;
import com.shao.Service.UserService;
import com.shao.Utils.responseDTO;
import com.shao.net.HttpRequest;
import com.shao.net.HttpResponseNIO;

@MyServlet("/GetAllUser")
public class GetAllUserServlet extends BaseServlet {
    responseDTO responseDTO = null;
    @Override
    void doGet(HttpRequest httpRequest, HttpResponseNIO httpResponse) {
        // 获取实例
        UserService userService = ServiceFactory.getUserService();

        // 调用获取所有用户的方法
        responseDTO = userService.GetAllUser();

        // 响应数据
        httpResponse.send(JSON.toJSONBytes(responseDTO));
    }
    @Override
    void doPost(HttpRequest httpRequest, HttpResponseNIO httpResponse) {
        responseDTO = new responseDTO(400, null, "不支持POST提交方法");
        httpResponse.send(JSON.toJSONBytes(responseDTO));
    }
}

6. 测试

八、作业

优化NIO

在高并发的场景下,现在的NIO配置无法及时处理,如何解决?

如果客户端发送的数据很多,如何分批次读取数据?

到目前为止,我们学习了 BIO和NIO网络通信模块、HttpRequest、HttpResponse、线程池、任务队列、线程任务对象、Servlet、业务逻辑处理 Service 、Dao 、数据库连接池、POJO、DTO、注解等。这些内容组合起来就是一个简单的框架

BIOS硬件监控实战:如何手动读取IT8738芯片的温度与风扇数据(附代码) 本文深入探讨了如何绕过操作系统和HWMonitor等监控软件,直接通过寄存器级操作读取IT8738超级I/O芯片的硬件监控数据。文章提供了从动态定位EC空间、构建底层读写函数到解码传感器寄存器映射的完整实战指南,并附有C语言代码示例,帮助开发者理解BIOS硬件监控的底层原理,适用于定制硬件开发与故障诊断。 阅读详情

相关推荐

调用D3D11硬解码和渲染VideoProcessor版本

在https://blog.youkuaiyun.com/robothn/article/details/78781321一文中使用shader来显示FFMPEG硬解码后的YUV420P,本文调用D3D11的videoprocessor来进行图像空间变换和尺寸变换,取得了较好的效果。 1.初始化D3D11设备、videodevice等数据结构 FFMPEG调用D3D11硬解码,获取其对应的device,videodevice。。。 FFMPEG使用av_hwdevice_find_type_by_name调用D3d11

zlyadvocate的博客 9285

手写Tomcat

tomcat提供的服务: 第一:提供Socket服务 第二:进行请求的分发 第三:需要把请求和响应封装成request/response

书生的博客 4098

逆向分析踩坑记:当Frida在x86模拟器上‘看不见’ARM的so文件时,我们该如何手动定位与验证?

本文探讨了在x86模拟器上使用Frida进行逆向分析时,无法检测到ARM架构so文件的解决方案。通过分析内存映射、Frida的视觉盲区及手动定位技术,提供了兼容层、混合调试和原生ARM环境三种实用方案,帮助逆向工程师突破工具限制,实现精准定位与验证。

weixin_27697385的博客 221

自己手写tomcat项目

在Servlet(接口中)有:1.init():初始化servlet2.getServletConfig():获取当前servlet的配置信息3.service():服务器(在HttpServlet中实现,目的是为了更好的匹配http的请求方式)4.getServletInfo():获取servlet当前运行过程中的信息5.destroy():销毁,回收内存在I/O中应包含:1.请求头(f12+网络) 2.请求方式(get/post) 3.请求内容。

2302_79585857的博客 1799

【重启后nvidia-smi 命令出现错误】

NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.

qq_44769377的博客 5211

逆变器技术解析:DDSRF双解耦在正负序分离中的关键作用

本文深入解析了DDSRF双解耦技术在逆变器正负序分离中的关键作用。通过建立正反旋转坐标系并利用交叉反馈解耦网络,DDSRF能快速、精准地分离电网电压中的正负序分量,从而显著提升锁相环在电网不平衡条件下的精度与系统稳定性,是现代高性能并网逆变器的核心算法之一。

m3n5b7v8c9x的博客 410

【学习笔记】手写 Tomcat -- 预备知识

I 是 Input,O 是Output,也就是输入输出流。当我们操作数据时,以内存为基准,把数据读取到内存中是输入,把数据从内存写入到硬盘是输出。

LearnTech_123的博客 1645

大学计算 - NumPy库的矩阵运算 实训答案

本文介绍了三个NumPy矩阵操作的实验练习。第一关练习ndarray类型操作,包括矩阵构造、元素平方和计算、矩阵乘积运算和逆矩阵行列式计算;第二关针对matrix类型,涉及绝对值最大值获取、特定矩阵乘积运算和转置矩阵特征值计算;第三关实现Moore-Penrose伪逆矩阵计算,并与NumPy内置pinv函数结果比较误差。实验涵盖了NumPy核心矩阵操作,展示了从基础运算到高级矩阵分解的应用,帮助掌握科学计算中的矩阵处理技巧。

2403_89314916的博客 310

【学习笔记】手写 Tomcat 六

昨天使用了数据库连接池,我们了解了连接池的优点,那么也可以使用线程池来管理线程,java自带的线程池的参数有 核心线程数,最大线程数,线程活跃时间,时间单位,任务队列,线程工厂,拒绝策略。为了学习了解线程池,我们先手写一个简单的线程池,只需要做到核心线程可重复利用就行。

LearnTech_123的博客 1763

5G/NR 网络切片基本概念(协议版)

26.1 网络切片概念 网络切片是一个概念,可以根据每个客户的要求进行区别对待。通过切片的形式,将不同流量差异化处理,以及可以将资源进行隔离,然后移动网络运营商可以将客户视为属于不同租户类型的客户,每种客户具有不同的服务要求,这些要求根据每个租户根据SLA (Service Level Agreement,服务水平协议)可以使用哪种切片类型进行管理和订阅。 网络切片始终由RAN部分和CN部...

欢迎来到小七的博客,这里将带你深入探索5G通信的神秘世界。无论你是通信领域的专业人士还是对这一领域充满好奇心的技术爱好者,这里都有专业协议解读、通信知识普及以及有趣的Python编程内容等你发现。 1万+

C++经典面试题100例及答案

答:把一些具有共性的对象归类后形成一个集合,也就是所谓的类。答:这样可以提高编译效率,因为分开的话只需要编译一次生成对应的.obj文件后,再次应用该类的地方,这个类就不会被再次编译,从而大大的提高了编译效率。答:这种函数会自动为内联函数,这种函数在函数调用的地方在编译阶段都会进行代码替换。答:常对象是指在任何场合都不能对其成员的值进行修改的对象。答:所谓的回调函数,就是预先在系统的对函数进行注册,让系统知道这个函数的存在,以后,当某个事件发生时,再调用这个函数对事件进行响应。

usstmiracle的博客 3万+

18_1手写Tomcat学习笔记

tomcat学习笔记 文章目录1 tomcat简介1.1 web服务器1.2 tomcat服务器1.2.1 下载1.2.2 安装1.2.3 配置1.2.4 tomcat目录结构1.2.5 如何去访问一个web应用的某个文件1.2.6 在web服务器中安装web应用1.2.7 配置虚拟目录1.2.8 虚拟主机1.3 浏览器访问web站点原理2 手写tomcat_静态资源3 手写tomcat_动态资源3.1 tomcat工作原理3.2 http get请求格式3.2 http post请...

tangguanlin2008的博客 3741

Cesium 实战 28 - 三维视频融合(视频投影)

Cesium 实战 27 - 三维视频融合(视频投影)。

非科班Java出身GISer的博客 3368

手写简易Tomcat

通过手写tomcat对java中的网络通信有了更进一步的了解

Java新生代 1411

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

【学习笔记】手写 Tomcat 二

在昨天的基础上,再进一步优化,能够响应HTML文件,图片等静态资源。

LearnTech_123的博客 1485

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

从零开始手写Tomcat,一文彻底搞懂Tomcat运行流程(附源码)

一:理论铺垫 tomcat的功能是什么? tomcat是java的一个中间件,浏览器发出HTTP请求后经过tomcat中间件,转发到目的服务器,目的服务器返回响应消息,通过tomcat返回给浏览器。tomcat的使用很简单,但是作为合格的程序员,光会用可不行,接下来就通过手写一个tomcat彻底搞懂tomcat。 在手写Tomcat之前,首先重温一下http和servlet,http协议...

Java鱼仔的博客 7765

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

【学习笔记】手写 Tomcat 五

我们把功能都写在了 Servlet,这样有几个缺点,一是不够低耦合 高内聚,二是不方便协同开发等。我们可以使用三层架构来解决这个问题。三层架构区分层次的目的是为了 “高内聚,低耦合”。

LearnTech_123的博客 1184

手写Tomcat框架

模型核心逻辑并发能力复杂度BIO一请求一线程,全程阻塞低简单NIO线程 + Selector 管多连接中高中等AIO异步通知,线程不等待高复杂2.扫描包的类用的是一个工具类进行实现的2.1首先 进行遍历获取类信息2.2通过反射机制,从目标类(clazz)中提取它上面标注的@WebServlet注解对象2.3这里获取类的无参构造方法 ---创建新的对象并强转向上转型为。

2302_80192044的博客 978

如何用JAVA手写一个Tomcat

Socket(套接字)是计算机网络中用于进程间通信的核心技术,它允许不同主机或同一主机上的不同程序通过网络交换数据Socket 是什么?定义:Socket 是操作系统提供的抽象接口,本质上是通信的端点(Endpoint)。它封装了底层网络协议(如TCP/IP或UDP)的复杂性,提供了一组简单的API【API(Application Programming Interface,应用程序编程接口)是软件系统之间交互的桥梁,定义了如何请求服务、传递数据以及返回结果的规则。】供应用程序使用。关键要素IP地址。

2301_80391652的博客 2580

手写一个Tomcat服务器

作为java开发者,都知道Tomcat是一个家户喻晓的Web服务器。手写一个Tomcat对我们理解Tomcat的工作原理,还有servlet的执行流程有很大的帮助,下面是我手写一个简要版Tomcat的总结和收获! 首先,先还原Tomcat的本质: 相信大家之前在开发的时候,虽然已经能上手开发web程序,但是对于Servlet的执行流程以及项目还会存在很多疑问,下面是我总结的我之前的疑问也给出相应...

yechengchao的博客 2051

Tomcat原理之手写

目录 一、准备工作 1.1 Tomcat概要 1.2 技术储备 二、实现步骤 三、相关类的实现和介绍 3.1 包结构 3.2 Servlet配置类 3.3 Tomcat实现类 3.4 请求响应实现类Request/Response 3.5 工具类HttpUtil/FileUtil 3.6 Servlet抽象和测试实现类 四、测试运行 4.1 成功请求servlet(200...

天天向上 1048

如何基于Netty手写简单的Tomcat?

Spring MVC 处理业务逻辑的,我们感知不到它的存在,平常我们只需要写Controller ,这是因为DispatcherServlet拦截了所有的请求。SpringBoot 提倡零配置,使用注解方式是Spring MVC 的主流。Spring 容器启动时会扫描相关类,并且j解析类上、方法上注解。类上URL作为基础路径和方法上URL拼接作为最终URL ,而对应方法即最终URL的处理器。相关的映射关系也被称为handler mappings。

happycao123的博客 1063

手写Tomcat(一)

Tomcat 服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。Servlet接口文件中定义的方法有以下几个:补充: GenericSrevlet类中实现了init()、getServletConfig()、getServletInfo()、destroy()四个方法,把service()交由HttpSrevlet实现。HttpServlet中关于 service()定义如下: 二、Tomca

m0_74154813的博客 2250
上一篇: 【学习笔记】手写 Tomcat 七
下一篇: 【学习笔记】手写一个简单的 Spring IOC
LearnTech_123
博客等级 码龄3年 445粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值