{"id":31886776,"url":"https://github.com/lltopk/handson-tomcat","last_synced_at":"2026-05-17T12:33:05.732Z","repository":{"id":270847464,"uuid":"911642217","full_name":"lltopk/handson-tomcat","owner":"lltopk","description":"手写传奇服务器Tomcat。handson-tomcat采用多分支开发，每个分支都是可运行的程度。领悟服务器设计哲学，攻克Web系统底层原理，带你卷向更高处","archived":false,"fork":false,"pushed_at":"2025-05-29T07:27:48.000Z","size":7883,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-13T05:48:07.594Z","etag":null,"topics":["java","servlet-api","tomcat","web"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lltopk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-01-03T13:56:15.000Z","updated_at":"2025-07-27T07:26:36.000Z","dependencies_parsed_at":"2025-01-03T14:45:16.329Z","dependency_job_id":"1a5f8796-29e1-4a0c-9722-e8116edc8cd4","html_url":"https://github.com/lltopk/handson-tomcat","commit_stats":null,"previous_names":["halfmoonly/handson-tomcat","brush4j/handson-tomcat","lltopk/handson-tomcat"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lltopk/handson-tomcat","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lltopk%2Fhandson-tomcat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lltopk%2Fhandson-tomcat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lltopk%2Fhandson-tomcat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lltopk%2Fhandson-tomcat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lltopk","download_url":"https://codeload.github.com/lltopk/handson-tomcat/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lltopk%2Fhandson-tomcat/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33138335,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-17T09:28:26.183Z","status":"ssl_error","status_checked_at":"2026-05-17T09:27:52.702Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","servlet-api","tomcat","web"],"created_at":"2025-10-13T05:48:05.175Z","updated_at":"2026-05-17T12:33:05.691Z","avatar_url":"https://github.com/lltopk.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# handson-tomcat\n当今微服务大行其道，Tomcat作为服务基石，功不可没\n\n感谢点星⭐⭐的朋友们，本仓库通过手写Tomcat，希望能够带着大家攻克Web系统底层原理，领悟服务器设计哲学，带你卷向更高处\n\nTomcat宏观架构如下：\n\n![img.png](architecture.png)\n\n在手写Tomcat之前，你需要先掌握HTTP请求/响应的基本格式：\n\nHTTP请求格式如下：\n- 第一行：请求方法 路径 协议/版本\n- 后面是请求头\n- 空一行\n- 请求体\n```shell\nGET /hello.txt HTTP/1.1\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\nAccept-Encoding: gzip, deflate, br\nAccept-Language: zh-CN,zh;q=0.9\nCache-Control: max-age=0\nConnection: keep-alive\nHost: localhost:8080\nSec-Fetch-Dest: document\nSec-Fetch-Mode: navigate\nSec-Fetch-Site: none\nSec-Fetch-User: ?1\nUpgrade-Insecure-Requests: 1\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36\nsec-ch-ua: \"Google Chrome\";v=\"113\", \"Chromium\";v=\"113\", \"Not-A.Brand\";v=\"24\"\n\n请求体（支持不同的类型如json、xml、x-www-form-urlencoded等）\n```\n\nHTTP响应格式类似：\n- 状态行: 协议/版本 响应码 msg\n- 响应头\n- 空行\n- 响应体\n```shell\nHTTP/1.1 200 OK\nContent-Type: text/html\nContent-Length: 12\nServer: tomcat\n\nHello World!\n```\nhandson-tomcat章节如下；\n- 一、服务层\n- 二、连接层\n- 三、容器层\n- 四、多应用\n- 五、集成Spring\n\n\u003e 第五章中，Spring部分的源码同样是手写，见我另一个仓库：https://github.com/Halfmoonly/handson-spring\n\n与`handson-spring`一样，`handson-tomcat`依旧采取多分支开发的方式，分支结构如下：\n- a-server01：实现一个最简单的静态资源服务器，根据请求返回基本的响应结构\n- a-server02：服务器引入`commons-lang3`，自定义动态资源`Servlet`，并支持`Servlet`内容动态填充\n- a-server03：服务器引入`javax.servlet-api`，对用户自定义的`Servlet`适配标准的`Servlet`规范\n- b-connector01：引入`Tomcat`连接层，同时对`HttpServer`一拆为二`Connector`和`Processor`，做到职责分离\n- b-connector02：提高服务器性能，实现`Processor`对象池\n- b-connector03：进一步提高服务器性能，设计线程`Processor`，同时实现与`Connector`线程之间的同步机制\n- b-connector04：对`Request`相关的代码适配`Servlet`规范，封装`RequestLine`并解析请求第一行信息，和`DefaultHeaders`请求头信息\n- b-connector05：对`Response`相关的代码适配`Servlet`规范，并进行响应码，响应头的解析\n- b-connector06：门面模式的应用，分别对`HttpRequest`和`HttpResponse`适配门面，选择性的隐藏内部细节\n- b-connector07：更进一步，对`HttpRequest`进行`GET`路径参数，以及`POST`请求体的解析，同时改造 SocketInputStream，由继承 InputStream 改为继承 ServletInputStream。使输入流适配Servlet规范\n- b-connector08：对请求侧设计`Cookie`，解析请求路径或者请求头`Cookie`中的`jsessionid`，对服务器设计存储`Sessions`集合`\u003cjsessionid,session\u003e`\n- b-connector09：对响应头设计`Set-Cookie`，使之有状态，终于可以把多次没有上下文关联的`HTTP`访问视为同一个用户访问。在 `Response` 返回参数中回写 `Session` 信息，使得客户端程序能够接受这个信息，下次请求 Server时携带Session信息\n- b-connector10：本节我们简单探讨了一下 `Keep-alive` 和 `chunked` 模式，让同一个 `Socket` 可以用于多次访问，减少了 `Socket` 的连接和关闭。\n- c-container-01：本节初步引入了容器的实现，`ServletContainer`，同时为了后续增强对Servlet生命周期的管理用ServletWrapper代替了Servlet\n- c-container-02：参考`Tomcat`项目结构，形成了两层容器，`ServletContext`(原ServletContainer)和`ServletWrapper`，`Tomcat` 把 `Wrapper` 也看作一种容器，也就是隶属于 Context 之下的子容器（Child Container）\n- c-container-03：引入逆序职责链模式`Pipeline+Valve`，`Valve`设计用于`Tomcat`容器间处理流程主机-\u003e引擎-\u003e应用程序，没有`url`模式，所以拦截所有应用程序/请求，不属于`Servlet`规范。注意同层容器内可以配置多个`Valve`并且是逆序触发的，因此每层容器中的基础阀`setBasic`用于触发下层容器执行\n  - 每层容器都通过抽象父类`ContainerBase`组合了`StandardPipeline pipeline`，`StandardPipeline`代表当前层容器的阀门集合，组合了`Valve valves[]`\n  - 父容器`StandardHost`指定基础阀为`StandardHostValve`，通过持有的`pipeline`触发子容器`StandardContext`\n  - 父容器`StandardContext`指定基础阀为`StandardContextValve`，通过持有的`pipeline`触发最后的容器`StandardWrapper`\n  - 父容器`StandardWrapper`指定基础阀为`StandardWrapperValve`，通过持有的`pipeline`构造和触发后续的过滤器`Filter`\n  - 过滤器`Filter`见下面的分支`c-container-04`，过滤器之后最终就会抵达用户`Servlet`应用\n- c-container-04：引入顺序职责链模式`Filter`，`Filter`设计主要用于`Tomcat`最后应用层面请求和响应处理，支持`url-parttern`仅拦截对给定应用程序的请求，属于`Servlet`规范\n- c-container-05：引入监听器`Listener`，首先定义了事件接口和监听接口，然后在容器`Container`启动过程中通过反射提前收集到所有用户配置的监听器实现，最后框架会在合适的位置执行用户的监听逻辑\n- d-mapp-01：通过引入更大的容器`StandardHost`，隔离`URLClassLoader`与`StandardContext`。隔离不同用户的应用路径加载，甚至是同名应用（不同路径代表不同版本：`jvm:classloader+classname`）隔离加载\n- d-mapp-02：自定义了类加载器用于打破`JVM`默认的双亲委派规则，分别是`CommonClassLoader`用于加载`lib`目录，以及`WebappClassLoader`用于加载用户`webapps`目录中的`Servlet`\n- d-mapp-03：引入 `server.xml` 和 `web.xml` 配置解析，分别管理 `Host` 启动配置与 `Servlet` 加载配置\n- e-itg-spring-01：独立服务器`Tomcat`托管`Spring`，`Spring`通过`ServletContextListener`接入`Tomcat`，而后`DispatcherServlet`接管了所有的Servlet流量。`Spring`只是作为`webapps`接入`Tomcat`，我们暂未考虑`Spring`嵌入`Tomcat`模式`embedded`\n- 更多分支正在更新中...\n\nmain分支包含以上所有功能特性，全量/增量开发文档见[docs](docs)目录\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flltopk%2Fhandson-tomcat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flltopk%2Fhandson-tomcat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flltopk%2Fhandson-tomcat/lists"}