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

简介: Tomcat 核心源码仿写的第二版代码,升级为Maven项目,并将单线程改为多线程

-- 更新信息 --

第一版代码实现了基本的交互功能,但只实现了单线程,此次迭代修改多线程,并升级为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()
        );
    }
目录
相关文章
|
7月前
|
安全 Java 应用服务中间件
阿里技术官架构使用总结:Spring+MyBatis源码+Tomcat架构解析等
分享Java技术文以及学习经验也有一段时间了,实际上作为程序员,我们都清楚学习的重要性,毕竟时代在发展,互联网之下,稍有一些落后可能就会被淘汰掉,因此我们需要不断去审视自己,通过学习来让自己得到相应的提升。
|
4月前
|
监控 网络协议 Java
Tomcat源码解析】整体架构组成及核心组件
Tomcat,原名Catalina,是一款优雅轻盈的Web服务器,自4.x版本起扩展了JSP、EL等功能,超越了单纯的Servlet容器范畴。Servlet是Sun公司为Java编程Web应用制定的规范,Tomcat作为Servlet容器,负责构建Request与Response对象,并执行业务逻辑。
Tomcat源码解析】整体架构组成及核心组件
|
7月前
|
设计模式 算法 前端开发
Tomcat的源码剖析, 启动过程你会吗?
基于JMX Tomcat会为每个组件进行注册过程,通过Registry管理起来,而Registry是基于JMX来实现的,因此在看组件的init和start过程实际上就是初始化MBean和触发MBean的start方法,会大量看到形如: Registry.getRegistry(null, null).invoke(mbeans, "init", false); Registry.getRegistry(null, null).invoke(mbeans, "start", false); 这样的代码,这实际上就是通过JMX管理各种组件的行为和生命期。
38 0
|
Java 应用服务中间件 数据格式
Tomcat 核心源码解析 及 仿写
介绍Tomcat的核心功能原理,并仿写Tomcat核心功能源码 包括: 1、如何生成Servlet实例对象并管理 2、如何与浏览器建立连接并获取http报文,解析报文获取请求,并响应 最后有效果演示和源码gitee地址
126 0
|
设计模式 Java 应用服务中间件
设计模式之责任链模式 Java实例代码 + Tomcat责任链模式应用+安卓责任链模式应用
设计模式之责任链模式 Java实例代码 + Tomcat责任链模式应用+安卓责任链模式应用
105 0
|
缓存 网络协议 应用服务中间件
手写Tomcat源码简易篇
手写Tomcat源码简易篇
|
Java 应用服务中间件 Maven
Tomcat - 源码构建Tomcat 8.5.55 启动
Tomcat - 源码构建Tomcat 8.5.55 启动
119 0
|
Java 应用服务中间件 容器
Tomcat8源码解析(二)
2.Tomcat启动阶段 daemon.start(),tomcat的启动阶段分析 getServer().start(),方法启动Server,源码分析 services[i].start(),启动
89 0
|
XML Java 应用服务中间件
Tomcat 安装使用&源码构建
Tomcat 安装使用&源码构建
128 0
|
Java 应用服务中间件 Maven
怎么读 Tomcat 源码?
上次分享了一篇关于 Tomcat 的文章《写一款 Tomcat 也没有那么难》,真有读者去下载了 Tomcat 的源码来研读,但搞了很久也没有把它在 IDEA 的开发环境给成功跑起来。
169 0
怎么读 Tomcat 源码?
下一篇
DataWorks