Netty練手項目-簡單Http服務器


 

 

  簡單的設計思路就是,啟動一個可以截斷並處理Http請求的服務器代碼。使用netty提供的boss線程與worker線程的模型,並使用netty的http解碼器。自行編寫了http url處理的部分。在接口層面,使用json作為格式。

  初始化掃描會指定掃描controller.container下的類,使用了自定義Annotation並且單例的方式加載,未考慮太多細節就為了好玩。

 

   接下來使用postman嘗試調用接口。

  一個簡單的netty搭建的web服務就完成了。

package server;

import handler.HttpServerHandler;
import initScan.InitialProcess;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;

/**
 * Created by MacBook on 2019/7/14.
 */
public class ServerStarter {

    private EventLoopGroup boss ;

    private EventLoopGroup worker ;

    private int port;

    private static int DEFAULT_PORT = 8080;

    public ServerStarter(){
        boss = new NioEventLoopGroup();
        worker = new NioEventLoopGroup();
        port = DEFAULT_PORT;
    }

    public ServerStarter(int port){
        this();
        if(port < 0 || port > 65535){
            throw new IllegalArgumentException("port:"+port+" is illegal");
        }
        this.port = port;
    }

    public void startup() throws InterruptedException{

        if(boss.isShutdown() || worker.isShutdown()){
            throw new IllegalStateException("server was closed");
        }

        // 初始化容器
        InitialProcess initialProcess = new InitialProcess();
        initialProcess.init();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        System.out.println("=====http server start ");
        serverBootstrap.channel(NioServerSocketChannel.class)
                .group(boss,worker)
                .childOption(ChannelOption.SO_KEEPALIVE,true)
                .option(ChannelOption.SO_BACKLOG,1024)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast("http-decode",new HttpServerCodec());
                        socketChannel.pipeline().addLast(new HttpServerHandler());
                    }
                });

        ChannelFuture future = serverBootstrap.bind(port).sync();

        System.out.println("server port listen:"+port);

        future.channel().closeFuture().sync();

        shutDownGracefully();
    }

    /**
     * 關閉管道
     */
    public void shutDownGracefully(){
        this.boss.shutdownGracefully();
        this.worker.shutdownGracefully();
    }

}

  這是服務器啟動的核心代碼,首先初始化兩個Nio線程組,把它們綁定到ServerBootstrap里,並添加Handler。

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import controller.Properties;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.*;
import response.BaseResponse;

import java.lang.reflect.Method;

/**
 * Created by MacBook on 2019/7/14.
 */
public class HttpServerHandler extends ChannelInboundHandlerAdapter{

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if(msg instanceof HttpRequest){
            HttpRequest request = (HttpRequest)msg;
//            boolean keepAlive = HttpUtil.isKeepAlive(request);

            System.out.println("http request method :"+request.method());
            System.out.println("http request uri : "+request.uri());

            Object controller = Properties.urlController.get(request.uri());
            Method m = Properties.urlMethod.get(request.uri());
            if(controller == null){
                FullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND);
                ctx.writeAndFlush(httpResponse).addListener(ChannelFutureListener.CLOSE);

            }else {
                FullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);

                httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json");
                Object result = m.invoke(controller);

                httpResponse.content().writeBytes(JSON.toJSONString(result,SerializerFeature.WriteMapNullValue).getBytes());

                ctx.writeAndFlush(httpResponse).addListener(ChannelFutureListener.CLOSE);
            }

        }
    }
}

  這是處理器的代碼,在經過第一個Http解碼器之后,進來的對象msg已經被轉化為HttpRequest了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM