
上节课我们自己动手制作了一个 RPC 框架,本节课我们挑战一个稍有难度的一点的任务,手动制作一个 Web 框架。考虑到 Java 的 web 框架被设计模式们坑的太惨,我不太愿意叫什么 MVC 框架,因为我在制作这个小项目的时候可没想过它要怎么怎么的 MVC,一切皆以易于使用和直观简单为目标。
首先我们看看这个 Web 框架使用起来如何简单
import httpkids.server.KidsRequestDispatcher; import httpkids.server.Router; import httpkids.server.internal.HttpServer; public class HelloWorld { public static void main(String[] args) { var rd = new KidsRequestDispatcher("/kids", new Router((ctx, req) -> { ctx.html("Hello, World"); })); new HttpServer("localhost", 8080, 2, 16, rd).start(); } } http://localhost:8080/kids KidsRequestDispatcher是请求派发器,用于将收到的 HTTP 请求对象扔给响应的RequestHandler进行处理。 Router用于构建路由,它负责的是将 URL 规则和RequestHandler挂接起来,形成一个复杂的映射表。
Router为了简化实现细节,所以没有支持复杂的 URL 规则,例如像RESTFUL这种将参数写在 URL 里面的这种形式是不支持的。
HttpServer是 Web 服务器的核心对象,构建 HttpServer 除了 IP 端口之外,还需要提供 3 个关键参数,分别是 IO 线程数、业务线程数和请求派发器对象。IO 线程用于处理套件字读写,由 Netty 内部管理。业务线程专门用于处理 HTTP 请求,由 httpkids 框架来管理。
import java.util.HashMap; import httpkids.server.KidsRequestDispatcher; import httpkids.server.Router; import httpkids.server.internal.HttpServer; public class HelloWorld { public static void main(String[] args) { var router = new Router((ctx, req) -> { ctx.html("Hello, World"); // 纯文本 html }) .handler("/hello.json", (ctx, req) -> { ctx.json(new String[] { "Hello", "World" }); // JSON API }) .handler("/hello", (ctx, req) -> { var res = new HashMap<String, Object>(); res.put("req", req); ctx.render("playground.ftl", res); // 模版渲染 }) .handler("/world", (ctx, req) -> { ctx.redirect("/hello"); // 302 跳转 }) .handler("/error", (ctx, req) -> { ctx.abort(500, "wtf"); // 异常 }) .resource("/pub", "/static") // 静态资源 .child("/user", () -> { // 路由嵌套 return new Router((ctx, req) -> { ctx.html("Hello, World"); }) .handler("/hello.json", (ctx, req) -> { ctx.json(new String[] { "Hello", "World" }); }) .filter((ctx, req, before) -> { // 过滤器、拦截器 if (before) { System.out.printf("before %s\n", req.path()); } else { System.out.printf("after %s\n", req.path()); } return true; }); }); var rd = new KidsRequestDispatcher("/kids", router); // 请求派发器 rd.templateRoot("/tpl") // 模版 classpath 根目录 .exception(500, (ctx, e) -> { // 异常处理 ctx.html("what the fuck it is", 500); }) .exception((ctx, e) -> { // 通用异常处理 ctx.html("mother fucker!", e.getStatus().code()); }); var server = new HttpServer("localhost", 8080, 2, 16, rd); server.start(); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { server.stop(); // 优雅停机 } }); } } http://localhost:8080/kids http://localhost:8080/kids/hello http://localhost:8080/kids/hello.json http://localhost:8080/kids/world http://localhost:8080/kids/error http://localhost:8080/kids/pub/bootstrap.min.css http://localhost:8080/kids/user http://localhost:8080/kids/user/hello 非 Java 程序员总是抱怨 Java 的框架过于复杂,特别爱拿 Java 恐怖的调用栈说事。比如下面这张图广为流传。
所以这里我要亮出 httpkids 的调用栈,我们来看看它到底有多深
HttpKids Web Framework based on Netty for Kids of You
RpcKids RPC Framework based on Netty for Kids of You
关注公众号「码洞」,让我们来一起研究一下这个框架的设计与实现。
1 Shynoob 2018 年 4 月 27 日 能提到 github 上吗 |
2 nine99 2018 年 4 月 27 日 看上去很牛啊 |
3 codehole OP |
5 awesomes 2018 年 4 月 27 日 建议最好从机器码开始 |
6 torbrowserbridge 2018 年 4 月 27 日 这个广告不行。完全没有关注的兴趣。 |
8 hsuan 2018 年 4 月 27 日 via Android 轮子谁都能造,关键是造的轮子能不能上路。 |
9 codehole OP @torbrowserbridge 广告的目的只是为了让好东西让更多的人看到 |
11 niubee1 2018 年 4 月 27 日 大凶带, 如果不是 Java 新版本加入了这些新特性, 你敢保证你不需要设计模式加持么? |
13 q397064399 2018 年 4 月 27 日 没有意义,轮子的 feature 不够,没有事务 没有 Redis 没有 ORM 没有 OAUTH2.0 没有事件 没有 AOP 一堆东西都没有, 要把这些东西集成到你这个框架,太难。 调用栈太多,麻烦的地方是排错,绝大部分程序员希望是有一个大而全的,且能够开箱即用的东西, 没人希望去造轮子。 |
14 codehole OP @q397064399 Go 的 Gin 和 Echo 框架都没有你说的这些东西,但是业界使用多着呢,node 的 express 框架也没有你说的这些东西,使用也是很广泛,python 的 tornado 虽然有 orm,但是也几乎无人使用这个 orm,照样阻挡不了它的流行。 另外 AOP 这个东西真不是必须有的。 |
15 codehole OP @q397064399 作为一个纯粹的 web 框架,httpkids 就是开箱即用的。 |
16 q397064399 2018 年 4 月 27 日 @codehole #14 等你业务大了,,需要权限 事务 审计的时候就用得到了 AOP,不过现在流行微服务, 权限 审计 都放到业务网关等地方做掉了,服务本身只需要关注业务逻辑了, 另外没有 ORM 静态语言组装对象太难受,哪怕是 mybatis 这种需要手写 sql 的框架,也省了不少的映射时间, |
17 Rhonin 2018 年 4 月 27 日 这里不是你的个人博客,也不是教学网站,不要在这里"讲课" |
18 misaka19000 2018 年 4 月 27 日 你这个设计理念是不是参考了 blade |
19 codehole OP @misaka19000 准确的说是 spark-java |
20 codehole OP @q397064399 ORM 你可以使用市面上的很多开源框架,简单组装一下就行了。不过再过几天,我会放出自己撸的一个 ORM 框架 |
21 deadEgg 2018 年 4 月 27 日 base on netty 我记得 netty 已经有人造过类似的轮子了吧。 |
23 xiangyuecn 2018 年 4 月 27 日 IIS、Tomcat 上来就是干,还是自己去撸有快感 打个广告先: https://www.jianshu.com/p/a06f9c74a439 nodejs 写的“简易 web 框架”,所有代码 100 行不到,支持 post、get 请求、任性复杂路由 |
24 wanderlustLee 2018 年 4 月 27 日 via iPhone 题主只是想靠自己的知识这个框架练手 为什么有这么多人来酸 题主支持你 |
25 codehole OP  [为什么 Java 总被黑?]( https://www.zhihu.com/question/36899399/answer/271363533) 我是冲着这个来的 |
26 jin5354 2018 年 4 月 27 日 v 友真的很严格 |