前言
文本已收录至我的GitHub仓库,欢送Star:https://github.com/bin392328206 > 种一棵树最好的工夫是十年前,其次是当初
six-finger-web
一个Web后端框架的轮子从解决Http申请【基于Netty的申请级Web服务器】 到mvc【接口封装转发)】,再到ioc【依赖注入】,aop【切面】,再到 rpc【近程过程调用】最初到orm【数据库操作】全副本人撸一个(繁难)的轮子。
github
为啥要写这个轮子
其实是这样的,小六六本人平时呢?有时候喜爱看看人家的源码比方Spring,然而小六六的程度可能不怎么样,每次看都看得昏头昏脑,而后就感觉外面的细节太难了,而后我就只能观其总体的思维,而后我就想我如果能够依据各位前辈的一些思考,本人撸一个简略的轮子进去,那我前面去了解作者的思维是不是简略点呢?于是呢 six-finger-web就面世了,它其实就是我的一个学习过程,而后我把它开源进去,心愿能帮忙那些对于学习源码有艰难的同学。还有就是能够锤炼一下本人的编码能力,因为平时咱们总是crud用的Java api都是那些,长此以往,很多框架类的api咱们基本就不纯熟了,所以借此机会,锤炼一下。
特点
- 内置由 Netty 编写 HTTP 服务器,无需额定依赖 Tomcat 之类的 web 服务(刚好小六六把Netty系列写完,顺便用下)
- 代码简略易懂(小六六本人写不出框架大佬那种高类聚,低耦合的代码),能力略微强一点看代码就能懂,弱点的也没关系,小六六有配套的从0搭建教程。
- 反对MVC相干的注解确保和SpringMVC的用法相似
- 反对Spring IOC 和Aop相干性能
- 反对相似于Mybatis相干性能
- 反对相似于Dubbo的rpc相干性能
- 对于数据返回,只反对Json格局
絮叨
此教程只适宜初中级程度,因为作者自身程度不高,不喜勿喷,明天是文章的第一篇,所以先写的是 由Netty 搭建一个http服务器
应用Netty实现HTTP服务器
Netty是一个异步事件驱动的网络应用程序框架用于疾速开发可保护的高性能协定服务器和客户端。Netty通过精心设计,具备丰盛的协定,如FTP,SMTP,HTTP以及各种二进制和基于文本的传统协定。
Java程序员在开发web利用的时候,咱们习惯于基于servlet标准,来做后端开发,就比方咱们的SpringMVC其本质也是一个servlet,至于spring Webfux,我不晓得有多少公司应用了,然而目前为止2020,咱们公司是没有应用的,这次呢咱们就试试用Netty来实现一下,其实这个很简略,以前的我写Netty系列的时候,我曾经写过了,大家能够去找找https://github.com/bin3923282...
首先是创立我的项目
因为咱们这个是six-finger-web的第一篇,所以我尽量把点点滴滴做到
首先创立一个maven我的项目,如果这个都不会的话,小六六倡议先学习根底再来,在文章很多的中央,一些根底的小六六是默认你懂,如果有啥不懂的能够上github上找我联系方式,我如果有空会给大家解答的
- 创立pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.xiaoliuliu</groupId> <artifactId>six-finger-web</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <dependencies> <!-- 为了代码简洁引入lombok,不须要再写setter和getter(能够不引入)--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope> </dependency> <!--动静代理相干--> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.1</version> </dependency> <!-- Netty相干--> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.51.Final</version> </dependency> </dependencies></project>
HttpServer
Netty 编写 HTTP 服务器主类
package com.xiaoliuliu.six.finger.web.server;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.nio.NioServerSocketChannel;import io.netty.handler.logging.LogLevel;import io.netty.handler.logging.LoggingHandler;import java.net.InetSocketAddress;/** * @author 小六六 * @version 1.0 * @date 2020/10/13 11:41 * Netty 编写 HTTP 服务器 * 主类 */public class HttpServer { /** * @Des 端口 http申请的端口 * @Author 小六六 * @Date 2020/10/13 11:42 * @Param * @Return */ int port; /** * @Des 构造方法 * @Author 小六六 * @Date 2020/10/13 11:42 * @Param * @Return */ public HttpServer(int port) { this.port = port; } /** * @Des 服务的启动办法 * @Author 小六六 * @Date 2020/10/13 11:43 * @Param * @Return */ public void start() throws Exception { //启动疏导类 ServerBootstrap bootstrap = new ServerBootstrap(); NioEventLoopGroup boss = new NioEventLoopGroup(); NioEventLoopGroup work = new NioEventLoopGroup(); bootstrap.group(boss, work) .handler(new LoggingHandler(LogLevel.DEBUG)) .channel(NioServerSocketChannel.class) .childHandler(new HttpServerInitializer()); ChannelFuture cf = bootstrap.bind(new InetSocketAddress(port)).sync(); System.out.println(" server start up on port : " + port); cf.channel().closeFuture().sync(); }}
HttpServerInitializer
package com.xiaoliuliu.six.finger.web.server;import io.netty.channel.ChannelHandler;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelPipeline;import io.netty.channel.socket.SocketChannel;import io.netty.handler.codec.http.HttpObjectAggregator;import io.netty.handler.codec.http.HttpServerCodec;/** * @author 小六六 * @version 1.0 * @date 2020/10/13 11:57 * 用于配置 pipeline的解决链 */public class HttpServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline pipeline = socketChannel.pipeline(); // http 编解码 pipeline.addLast(new HttpServerCodec()); // http 音讯聚合器 pipeline.addLast("httpAggregator",new HttpObjectAggregator(512*1024)); // 申请处理器 pipeline.addLast(new HttpRequestHandler()); }}
HttpRequestHandler
package com.xiaoliuliu.six.finger.web.server;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelFutureListener;import io.netty.channel.ChannelHandler;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.handler.codec.http.*;import io.netty.util.AsciiString;import io.netty.util.CharsetUtil;import java.util.HashMap;import java.util.Map;import static io.netty.handler.codec.http.HttpUtil.is100ContinueExpected;/** * @author 小六六 * @version 1.0 * @date 2020/10/13 12:01 * 外围解决http申请的类,包含url的匹配外围办法都是在channelRead0办法 */public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> { private static final String FAVICON_ICO = "/favicon.ico"; private static final AsciiString CONNECTION = AsciiString.cached("Connection"); private static final AsciiString KEEP_ALIVE = AsciiString.cached("keep-alive"); @Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); } @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception { System.out.println("取得的参数:"+req); if (is100ContinueExpected(req)) { ctx.write(new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE)); } // 获取申请的uri String uri = req.uri(); Map<String,String> resMap = new HashMap<>(); resMap.put("method",req.method().name()); resMap.put("uri",uri); String msg = "<html><head><title>小六六揭示你</title></head><body>你申请uri为:" + uri+"</body></html>"; // 创立http响应 DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8)); //设置头信息 response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8"); //把音讯输入到浏览器 ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); }}
ApplicationServer 测试类
package com.xiaoliuliu.six.finger.web.demo.server;import com.xiaoliuliu.six.finger.web.server.HttpServer;/** * @author 小六六 * @version 1.0 * @date 2020/10/13 14:26 * 这个类 用于 搭建Netty web服务器的测试类,只实用于搭建教程的第一篇文章 */public class ApplicationServer { public static void main(String[] args) throws Exception { HttpServer server = new HttpServer(8081);// 8081为启动端口 server.start(); }}
测试后果
在浏览器上输出
http://localhost:8081/xiaoliuliu
咱们看看输入
而后咱们来看看控制台
发现多了一次申请,这个是什么起因呢?
这是因为HttpRequestDecoder把申请拆分成HttpRequest和HttpContent两局部,
所以咱们要过滤哪个/favicon.ico的申请,所以改改代码
if("/favicon.ico".equals(uri)) { System.out.println("申请了 favicon.ico, 不做响应"); return; }```## 结尾好了,明天咱们用几十行代码实现了一个简略的Http服务器,很多的细节咱们一一解说,然而我的正文基本上都写了,如果你有看不懂的中央,欢送你来找我,我有空会给大家解答的,而后下一章就是咱们要写的SpringMVC相干的代码了。## 日常求赞> 好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是**真粉**。> 创作不易,各位的反对和认可,就是我创作的最大能源,咱们下篇文章