preface

Text has been included to my lot warehouse, welcome Star:https://github.com/bin392328206 plant a tree is the best time ten years ago, followed by now

six-finger-web

The wheels of a Web backend framework roll themselves (easy) from handling Http requests [Netty request-level Web servers] to MVC [interface encapsulating and forwarding], to IOC [dependency injection], to AOP [aspect], to RPC [remote procedure calls] and finally to ORM [database operations].

github

Why the wheel

Actually is such, small six six oneself peacetime? Sometimes like to look at the source code such as Spring, but the level may not how, every time dazed at all, and then feel the inside of the details too difficult, then I can only view the overall thought, then I think if I can according to each elder some thought, rolled out a simple wheel, Is it easier for me to understand the author’s ideas? So six-Finger-Web came out, and it was really a learning process for me, and THEN I opened it up to help those of you who are having trouble learning the source code. In addition, we can exercise our coding ability, because we usually use Java API for CRUD. As time goes by, we are not familiar with many framework API classes, so we take this opportunity to exercise.

The characteristics of

  • Built-in HTTP server written by Netty, without additional dependence on Web services such as Tomcat.
  • Code is simple to understand (small 66 can not write their own framework big guy that kind of high clustering, low coupling code), ability a little bit stronger to see the code can understand, weakness also does not matter, small 66 has a supporting from 0 build tutorial.
  • Support MVC-related annotations to ensure that they are used similarly to SpringMVC
  • Support for Spring IOC and Aop related features
  • Support similar to Mybatis related functions
  • Supports RPC-related functionality similar to Dubbo
  • For data returns, only the Json format is supported

omg

This tutorial is only suitable for the middle level, because the author’s own level is not high, do not like spraying, today is the first article, so the first to write is by Netty build an HTTP server

Use Netty to implement HTTP server

Netty is an asynchronous event-driven network application framework for rapid development of maintainable high-performance protocol servers and clients. Netty is well designed with rich protocols such as FTP, SMTP, HTTP and a variety of binary and text-based traditional protocols.

When Java programmers develop Web applications, we are used to doing back-end development based on the Servlet specification. For example, our SpringMVC is essentially a servlet. As for Spring Webfux, I don’t know how many companies are using it, but so far in 2020, Our company is of no use, this time we just try Netty to realize, actually this is very simple, before I write Netty series, I have already written, you can look for https://github.com/bin392328206/six-finger

The first is to create the project

Since this is our first post on the Six-Finger-Web, I’m trying to do everything I can

First of all, create a Maven project, if this is not able to, xiao Liuliu suggested to learn the basics first, in many articles, some basic xiao Liuliu is the default you understand, if what do not understand you can find my contact information on Github, I will answer you if free

  • Create the 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">
The < modelVersion > 4.0.0 < / modelVersion >  <groupId>com.xiaoliuliu</groupId>  <artifactId>six-finger-web</artifactId>  <packaging>jar</packaging> < version > 1.0 - the SNAPSHOT < / version >  <dependencies> <! -- Introducing Lombok for code brevity, no need to write setters and getters --> <dependency>  <groupId>org.projectlombok</groupId>  <artifactId>lombok</artifactId> The < version > 1.18.12 < / version > <scope>provided</scope>  </dependency> <! -- Dynamic proxy correlation --> <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> Copy the code

HttpServer

Netty writes the HTTP server main class

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 little six six* @ version 1.0 * @date 2020/10/13 11:41 * Netty writes the HTTP server* the main class* /public class HttpServer {  / * ** @DES Port Indicates the HTTP request port* @author little six six * @Date 2020/10/13 11:42  * @Param  * @Return * / int port;   / * ** @des constructor* @author little six six * @Date 2020/10/13 11:42  * @Param  * @Return * / public HttpServer(int port) {  this.port = port;  }  / * ** @des service startup method* @author little six six * @Date 2020/10/13 11:43  * @Param  * @Return * / public void start() throws Exception { // Start the bootstrap class 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();  } }  Copy the code

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 little six six* @ version 1.0 * @date 2020/10/13 11:57 * Used to configure the pipeline's processing chain* /public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {   @Override  protected void initChannel(SocketChannel socketChannel) throws Exception {  ChannelPipeline pipeline = socketChannel.pipeline(); // HTTP codec pipeline.addLast(new HttpServerCodec()); // HTTP message aggregator pipeline.addLast("httpAggregator",new HttpObjectAggregator(512*1024)); // Request handler pipeline.addLast(new HttpRequestHandler());  } } Copy the code

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 little six six* @ version 1.0 * @date 2020/10/13 12:01 * The core classes that handle HTTP requests, including the url matching core methods, are in the channelRead0 method* /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("Obtained parameters :"+req);  if (is100ContinueExpected(req)) {  ctx.write(new DefaultFullHttpResponse(  HttpVersion.HTTP_1_1,  HttpResponseStatus.CONTINUE));  } // Get the request URI String uri = req.uri();  Map<String,String> resMap = new HashMap<>();  resMap.put("method",req.method().name());  resMap.put("uri",uri);  String msg = "< HTML >  You request uri is:" + uri+"</body></html>"; // Create an HTTP response DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,  HttpResponseStatus.OK,  Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));  // Set the header information response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");  // Outputs the message to the browser ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);   }   @Override  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {  cause.printStackTrace();  ctx.close();  } }  Copy the code

Application server test class

package com.xiaoliuliu.six.finger.web.demo.server;

import com.xiaoliuliu.six.finger.web.server.HttpServer;

/ * ** @author little six six* @ version 1.0 * @date 2020/10/13 14:26 * This class is a test class for building a Netty Web server and is only suitable for the first article of the Building tutorial* /public class ApplicationServer {  public static void main(String[] args) throws Exception { HttpServer server = new HttpServer(8081); // 8081 is the boot port server.start();  } } Copy the code

The test results

Type in your browser

http://localhost:8081/xiaoliuliu

Let’s look at the output


Then let’s look at the console


Found one more request, what is the reason for this?

This is because HttpRequestDecoder splits the request into HttpRequest and HttpContent,

So we want to filter which /favicon.ico request, so change the code

    if("/favicon.ico".equals(uri)) {
            System.out.println("Requested favicon.ico, no response");
            return;
        }
Copy the code

At the end

Ok, today we have implemented a simple Http server with dozens of lines of code, we will explain a lot of details, but my comments are basically written, if you do not understand the place, you are welcome to come to me, I will give you some answers, and then the next chapter is we will write SpringMVC code.

Daily for praise

Ok, everybody, that’s all for this article, you can see people here, they are real fans.

Creation is not easy, your support and recognition, is the biggest power of my creation, our next article

Six pulse excalibur | article “original” if there are any errors in this blog, please give criticisms, be obliged!