最通俗易懂的 - Tomcat 核心源码仿写 第二版代码

本文介绍了对Tomcat代码的迭代更新,从单线程版本升级到使用Maven项目结构,并优化代码以提高可读性。重点在于引入线程池处理HTTP请求,通过YAML配置文件管理线程池参数,以及处理浏览器自动请求favicon.ico的机制。
摘要由CSDN通过智能技术生成

– 更新信息 –

第一版代码实现了基本的交互功能,但只实现了单线程,此次迭代修改多线程,并升级为Maven项目,同时优化代码排版,提高代码可读性

第一版代码介绍博客地址:最通俗易懂的 - Tomcat 核心源码仿写

– 源码地址 –
朱元杰的开源仓库 – Tomcat核心源码仿写

– 正文内容 –

直接上main方法代码:

public static void main(String[] args) throws IOException {

        //创建JUL日志执行器
        Logger myTomcatLogger = Logger.getLogger("MyTomcat");

        //创建线程池
        ThreadPoolExecutor threadPoolExecutor = createThreadPoolExecutor();

        //启动阶段
        startupPhase(myTomcatLogger);

        //注册端口
        InetAddress localHost = InetAddress.getLocalHost();
        myTomcatLogger.info("当前服务器信息:" + localHost);
        ServerSocket serverSocket = new ServerSocket(8080, 10, localHost);

        while (true) {

            myTomcatLogger.info("等待建立连接 - " + connectSerialNumber);
            Socket socket = serverSocket.accept();
            myTomcatLogger.info("连接已建立 - " + connectSerialNumber);
            connectSerialNumber++;

            threadPoolExecutor.execute(() -> {

                //接收Http请求报文
                ArrayList<String> httpMessage = receiveHttp(socket, myTomcatLogger);

                //处理请求
                //获取请求方式
                String httpHead = httpMessage.get(0);
                String requestStyle = httpHead.split(" ")[0];

                if (requestStyle.equals("GET")) {

                    String requestPathAndParameter = httpHead.split(" ")[1];

                    //创建HttpRequest对象
                    MyHttpRequest myHttpRequest = new MyHttpRequest();

                    //获取请求路径,并将参数置入HttpRequest对象
                    String requestPath = getRequestPathAndSetMyHttpRequest(requestPathAndParameter, myHttpRequest, myTomcatLogger);

                    //还没处理 favicon.ico 请求,先屏蔽
                    if (requestPath.equals("favicon.ico")) {
                        myTomcatLogger.info("暂时无法响应 favicon.ico");
                        return;
                    }

                    //创建HttpResponse对象
                    MyHttpResponse myHttpResponse = getMyHttpResponse(socket);

                    //反射调用Servlet方法
                    servletActuator(requestPath, "doGet", myHttpRequest, myHttpResponse);

                } else {
                    myTomcatLogger.info("还未开通其他请求方式.....");
                }
            });
        }

本次引入线程池,将交互的内容交给线程池完成,main方法负责建立socket连接

可以看到有个while(true)循环,不断建立socket连接,建立起连接后就将连接丢给threadPoolExecutor.execute 去处理

在 threadPoolExecutor.execute 中完成的还是那几步:

  1. 接收Http请求报文
  2. 获取请求路径和请求参数
  3. 创建出 HttpRequest 和 HttpResponse 对象
  4. 通过反射调用请求路径对应的 servlet 方法

我将每一步的具体实现方法都封装成了一个方法,需要的就去我的Gitee上拿源码吧

另外,通过配置文件配置线程池的方法如下:

  1. 引入 org.yaml 依赖,因为我是通过 yml 文件进行配置的
		<dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.29</version>
        </dependency>
  1. 在resources 文件下编写配置文件 config.yml 内容如下:
thread:
  pool:
    coreSize: 5
    maxSize: 10
    keepAliveTime: 60
    workQueueSize: 1000
  1. 接着就可以创建线程池了
    private static ThreadPoolExecutor createThreadPoolExecutor() throws FileNotFoundException {
        //读取yml配置文件
        Yaml yaml = new Yaml();
        InputStream inputStream = new FileInputStream("src\\main\\resources\\config.yml");
        Map<String, Object> threadPoolMap = new HashMap<>();
        threadPoolMap = yaml.load(inputStream);
        Map<String, Map<String, Object>> poolMap = (Map<String, Map<String, Object>>) threadPoolMap.get("thread");
        //创建线程池
        return new ThreadPoolExecutor(
                (Integer) poolMap.get("pool").get("coreSize"),
                (Integer) poolMap.get("pool").get("maxSize"),
                (Integer) poolMap.get("pool").get("keepAliveTime"),
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>((Integer) poolMap.get("pool").get("workQueueSize")),
                new ThreadPoolExecutor.AbortPolicy()
        );
    }

现在已经可以进行多台主机的连续请求,效果如下:

第一次请求:
在这里插入图片描述
第二次请求 - 修改请求地址为 address2(出现了乱码问题,不过问题不大嘿嘿):
在这里插入图片描述

查看控制台输出:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实际上这边总共有四次请求,这是因为每次我们发送请求时,浏览器都会自动发出一个请求来获取网站的 favicon.ico 文件。favicon.ico 是网站的小图标,通常位于网站的根目录下。这个请求是浏览器自动发出的,不需要用户手动触发。

另外一个可以看到,当前都是基于 Http 1.1 的请求, Http 1.1 是短链接,因此每一次请求都要建立一次socket连接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值