手写Tomcat(一) | 草台班子

LOADING

加载过慢请开启缓存 浏览器默认开启

手写Tomcat(一)

写在前面的一些心里话
大三开学以来心力交瘁,感觉是大学以来最累的一段时光,家长催着考研,自己心里也不坚定。
身边的朋友不少已经实习,落雨甚至都从字节跑回来了,感觉自己进度太慢,焦虑愈发严重。
本打算九月十月准备好项目,十一月开投,在寒假后做一个了断(考研还是就业)
结果九月实验室招新一堆事儿,十月份天天熬夜总算肝完了头条,白头发也多了不少,十一月还没开始写简历就病一场,病好后各种考试实验接踵而至。
同时又报了字节青训营,那边Go的进度也落下不少,拖欠了快十节课没看了。深感一心不能多用,心里也慢慢的倾向考研了。一来提升学历二来延长学习时间
不过实习还是要试试的,大概在寒假前投一投看看吧。下周开始平均下来一天只有一节课了,虽然有考试压力,但时间还是充沛的,放下项目和八股,来实施我心里一直想做的一件事
手搓web服务器!!!

最开始的打算是用Go写的,不过我并不满足于demo,而是想搓一个能部署web项目的服务器来,所以还是拿自己学的最久的Java来罢
现在犹记得大一刚开始写Javaweb的时候,费老半天劲儿下了tomact往上面部署项目,才发现springboot内置tomact之后气急败坏的情形(
tomact也算是最流行的开源web服务器了,我当然不敢说完全照着来,能实现一部分功能(当然,最基本的是能部署项目)我就深感荣幸

Tomcat架构

在网上扒拉了些文章,最后发现b站的视频讲的最清楚,Tomcat架构应当如下
img.png

这也解释了为什么一台电脑能部署多个网站
请求消息中的主机名被连接器识别出来放入request,然后根据request中的主机名,找到对应的虚拟主机,然后把请求转发给虚拟主机处理

  • 一台虚拟主机中通常部署多个应用,一个应用对应一个context对象
  • context中又有多个不同的servlet,每个servlet可以有多个不同的实例,同一个servlet的所有实例交给一个容器wrapper管理
  • 实际上这里的engine、host、context、wrapper都是容器
  • 连接器最后将response对象转换为字节流返回给浏览器
  • img_1.png

url发出之后

首先会根据域名(例如www.itsme.com)定位到host,然后再根据后面的路径(例如/qwer)定位到context中,context中就是我们webApp了,一个context中只能包含一个webApp
当然,不能忽视了连接器connector,tomcat支持https、http多种类型的连接器,我的打算是只做http的,类似于https的验证功能交给nginx,把他充当一个小型网关,这些都是后话了

Web服务器本质上是实现接口

在学习之前我一直以为是Java要实现服务器的规范,刚看的Tomcat中要实现JavaAPI的时候我也感到不可置信,直到后面才发现能用Tomcat部署的服务只有Java和JSP。。。可以说是为Java量身打造了

这里就不得不提到Java Servlet API的规范了
Java Servlet API的规范,用于定义Web服务器如何处理HTTP请求和响应。

摘自廖雪峰

Servlet规范有一组接口,对于Web App来说,操作的是接口,而真正对应的实现类,则由各个Web Server实现,这样一来,Java Web App实际上编译的时候仅用到了Servlet规范定义的接口,只要每个Web服务器在实现Servlet接口时严格按照规范实现,就可以保证一个Web App可以正常运行在多种Web服务器上
当Servlet容器接收到用户的HTTP请求后,由容器负责把请求转换为HttpServletRequest和HttpServletResponse对象,分别代表HTTP请求和响应,然后,经过若干个Filter组件后,到达最终的Servlet组件,由Servlet组件完成HTTP处理,将响应写入HttpServletResponse对象

开始动手后的一些发现

第一天主要耗费在了查询资料和了解架构以及构思上,知道最后开始动手写代码时才发现Java几乎以及准备好了一切。。。
HttpExchange————request和response的转换,内置Headers的封装
img_2.png
不过正是如此,让我可以更专注的实现Servlet的内容,如果以后有再深入的机会,可能会尝试下定制请求头这些轮子吧
ps:在阅读Headers源码的时候的一点有趣的小发现
img_3.png
朴实无华的标准化HTTP 头部字段的名称方法