自己用Java写一个HTTP服务器和MVC框架
自己刚实现了一个轻量级的嵌入式http服务器,Java语言,基于nio。
同时提供类似spring mvc的功能, 包括@Controller,@RequestMapping,参数注入等功能。
项目地址:LightWebServer
项目总计1700行java代码, {理解原理 + 不实现}三天左右,{理解原理 + 自己实现}需要一周左右。
下面分享一下自己的学习步骤:
1.学习nio相关知识
简单来说nio是用来处理socket连接的,包括:
- 建立服务端和客户端之间的连接
- 从socket读数据(读http request的数据)
- 往socket写数据(写http response的数据)
注:服务端监听客户端发起的连接请求。浏览器,postman插件,idea的TEST RESTful Web Service插件,自己写的发送http请求的代码等都可以看成客户端。
nio学习路线:通道 -> 选择器 -> 缓冲区(千万不要按书中的顺序一开始就学缓冲区API, 头会晕的)。学完后用nio处理的这一部分完整代码在这。目前没有实现keep-alive,一个线程(选择器所在线程)管理多个通道(nio核心理念)。读取完一个请求后开一个线程(RequestHandler类)处理http请求。
public void read(SelectionKey key) throws IOException { SocketChannel client = (SocketChannel) key.channel(); ThreadPool.execute(new RequestHandler(client, selector)); key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);//目前一个请求对应一个socket连接,没有实现keep-alive }
2.解析http请求(parse http request)
3.生成http响应(generate http response)
因为需要做springmvc中类似@Controller和@RequestMapping功能,所以需要做以下两件事
- 扫描所有被@Controller注解的类和该类中被@RequestMapping注解的方法
- 找到对应的方法去执行请求,方法返回com.light.http.responses.Response。
4.将响应写回给客户端
public void write(SelectionKey key) throws IOException { SocketChannel client = (SocketChannel) key.channel(); Response response = (Response) key.attachment();//从key中取出response ByteBuffer byteBuffer = response.getResponseBuffer(); if(byteBuffer.hasRemaining()){ client.write(byteBuffer); } if(!byteBuffer.hasRemaining()){ key.cancel(); client.close(); } }
References
- HTTP规范
- nio教程