上节课我们自己动手制作了一个 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-04-27 11:04:15 +08:00
能提到 github 上吗
|
2
nine99 2018-04-27 11:50:31 +08:00
看上去很牛啊
|
3
codehole OP |
5
awesomes 2018-04-27 12:02:42 +08:00
建议最好从机器码开始
|
6
torbrowserbridge 2018-04-27 12:03:45 +08:00
这个广告不行。完全没有关注的兴趣。
|
8
hsuan 2018-04-27 12:04:46 +08:00 via Android
轮子谁都能造,关键是造的轮子能不能上路。
|
9
codehole OP @torbrowserbridge 广告的目的只是为了让好东西让更多的人看到
|
11
niubee1 2018-04-27 12:19:35 +08:00 1
大凶带, 如果不是 Java 新版本加入了这些新特性, 你敢保证你不需要设计模式加持么?
|
13
q397064399 2018-04-27 13:16:19 +08:00
没有意义,轮子的 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-04-27 14:05:33 +08:00
@codehole #14 等你业务大了,,需要权限 事务 审计的时候就用得到了 AOP,不过现在流行微服务, 权限 审计 都放到业务网关等地方做掉了,服务本身只需要关注业务逻辑了, 另外没有 ORM 静态语言组装对象太难受,哪怕是 mybatis 这种需要手写 sql 的框架,也省了不少的映射时间,
|
17
Rhonin 2018-04-27 14:09:05 +08:00
这里不是你的个人博客,也不是教学网站,不要在这里"讲课"
|
18
misaka19000 2018-04-27 14:12:18 +08:00
你这个设计理念是不是参考了 blade
|
19
codehole OP @misaka19000 准确的说是 spark-java
|
20
codehole OP @q397064399 ORM 你可以使用市面上的很多开源框架,简单组装一下就行了。不过再过几天,我会放出自己撸的一个 ORM 框架
|
21
deadEgg 2018-04-27 14:29:47 +08:00
base on netty
我记得 netty 已经有人造过类似的轮子了吧。 |
23
xiangyuecn 2018-04-27 14:31:30 +08:00
IIS、Tomcat 上来就是干,还是自己去撸有快感
打个广告先: https://www.jianshu.com/p/a06f9c74a439 nodejs 写的“简易 web 框架”,所有代码 100 行不到,支持 post、get 请求、任性复杂路由 |
24
wanderlustLee 2018-04-27 14:32:17 +08:00 via iPhone 2
题主只是想靠自己的知识这个框架练手 为什么有这么多人来酸 题主支持你
|
25
codehole OP ![为什么 Java 总被黑?]( https://user-gold-cdn.xitu.io/2018/4/27/16305d1dcfb7e54c?w=897&h=573&f=png&s=156446)
[为什么 Java 总被黑?]( https://www.zhihu.com/question/36899399/answer/271363533) 我是冲着这个来的 |
26
jin5354 2018-04-27 14:45:30 +08:00
v 友真的很严格
|