netty 手动实现tomcat的简单功能

Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现。现在我们通过netty来实现一些Tomcat的简单功能。

//1、启动端口(IP),默认8080 , ServerSocket localhost:IP
//2、配置web.xml 自己写的Servlet需要继承HttpServlet
//servlet-url
//servlet-class
//servlet-name
//3、读取配置url-pattern 和 Servlet建立一个映射关系
//4、HTTP请求,发送的就是一些有规律的字符串,(HTTP协议)
//5、从协议中拿到URL,通过反射实例化Servlet对象
//6、最后条用doGet或者doPost进行逻辑处理
//7、Request()、Response()

废话不多说,直接上代码:

1、TomcatServer

package com.lh.study.rpc.io.tomcat.v1;

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.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;

/**
 * @description:
 * @author: lianghao
 * @create: 8/5/2019 5:52 PM
 **/
public class TomcatServer {

    public void start(int port){
        EventLoopGroup workGroup = new NioEventLoopGroup();
        EventLoopGroup bossGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup,workGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                // 无锁化串行编程
                // HttpResponseEncoder 编码器
                socketChannel.pipeline().addLast(new HttpResponseEncoder());
                // HttpRequestDecoder 解码器
                socketChannel.pipeline().addLast(new HttpRequestDecoder());
                // 业务逻辑处理
                socketChannel.pipeline().addLast(new LhTomcatHandler());
            }
        })
                // 针对主线程的配置 分配线程最大数量 128
                .option(ChannelOption.SO_BACKLOG, 128)
                // 针对子线程的配置 保持长连接
                .childOption(ChannelOption.SO_KEEPALIVE, true);

        try {
            ChannelFuture future = serverBootstrap.bind(port).sync();
            System.out.println("Tomcat start port:"+port);
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            if(null != workGroup){
                workGroup.shutdownGracefully();
                bossGroup.shutdownGracefully();
            }
        }
    }

    public static void main(String[] args) {
        new TomcatServer().start(8088);
    }
}

2、LhTomcatHandler

package com.lh.study.rpc.io.tomcat.v1;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;

import java.lang.reflect.Method;
import java.util.List;

/**
 * @description:
 * @author: lianghao
 * @create: 8/6/2019 9:17 AM
 * @email: hao.liang.ext@siemens.com
 **/
public class LhTomcatHandler extends ChannelInboundHandlerAdapter {



    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
       if(msg instanceof HttpRequest){
           HttpRequest httpRequest = (HttpRequest)msg;
           LhResponse response = new LhResponse(ctx , httpRequest);
           LhRequest request = new LhRequest(ctx , httpRequest);
           String uri = request.getUri();
           if(uri.indexOf("?") >=0){
               uri = request.getUri().substring(0 , uri.indexOf("?"));
           }
           ServletMappingHandle servletMappingHandle = patternUrl(uri);
           if(null == servletMappingHandle){
               response.write("404 Not Found");
               return;
           }
           Class<?> clazz = Class.forName(servletMappingHandle.getServletClassName());
           Method method = null;
           HttpMethod httpMethod = request.getMethod();
           if(httpMethod.equals(HttpMethod.GET)){
               method = clazz.getMethod("doGet" , new  Class<?>[]{LhRequest.class , LhResponse.class});
           }else{
               method = clazz.getMethod("doPost" , new  Class<?>[]{LhRequest.class , LhResponse.class});
           }
           method.invoke(clazz.newInstance() , new Object[]{request , response});
       }
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }

    private ServletMappingHandle patternUrl(String uri){
        List<ServletMappingHandle> servletMappingHandles = ServletMappingHandle.servletMappingHandleList;
        for(ServletMappingHandle servletMappingHandle : servletMappingHandles){
            if(servletMappingHandle.getServletUrl().equals(uri)){
                return servletMappingHandle;
            }
        }
        return null;
    }
}

3、ServletMappingHandle

package com.lh.study.rpc.io.tomcat.v1;

import java.util.ArrayList;
import java.util.List;

/**
 * @description:
 * @author: lianghao
 * @create: 8/14/2019 5:13 PM
 **/
public class ServletMappingHandle {

    private String servletUrl;

    private String servletClassName;

    public static List<ServletMappingHandle> servletMappingHandleList  = new ArrayList<>();
    public ServletMappingHandle(){

    }
    public ServletMappingHandle(String servletUrl, String servletClassName) {
        this.servletUrl = servletUrl;
        this.servletClassName = servletClassName;
    }

    public String getServletUrl() {
        return servletUrl;
    }

    public void setServletUrl(String servletUrl) {
        this.servletUrl = servletUrl;
    }

    public String getServletClassName() {
        return servletClassName;
    }

    public void setServletClassName(String servletClassName) {
        this.servletClassName = servletClassName;
    }

    static {
        /**这里简化了读取web.xml的,直接手动封装了访问URl和servlet的对应关系*/
     
        servletMappingHandleList.add(new ServletMappingHandle("/test" , "com.lh.study.rpc.io.tomcat.v1.LhServletImpl"));
    }
}

4、LhRequest

package com.lh.study.rpc.io.tomcat.v1;

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;

import java.util.List;
import java.util.Map;

/**
 * @description:
 * @author: lianghao
 * @create: 8/6/2019 9:21 AM
 **/
public class LhRequest {

    private ChannelHandlerContext ctx;

    private HttpRequest httpRequest;

    public LhRequest(ChannelHandlerContext ctx, HttpRequest httpRequest) {
        this.ctx = ctx;
        this.httpRequest = httpRequest;
    }

    /**
     * 获取请求的uri
     * @return 返回请求路径
     */
    public String getUri(){
        return httpRequest.uri();
    }

    public HttpMethod getMethod(){
        return httpRequest.method();
    }

    public Map<String , List<String>> getParams(){
        QueryStringDecoder queryStringDecoder = new QueryStringDecoder(getUri());
        return queryStringDecoder.parameters();
    }

    public List<String> getParamByName(String name){
        return getParams().get(name);
    }

    public ChannelHandlerContext getCtx() {
        return ctx;
    }

    public void setCtx(ChannelHandlerContext ctx) {
        this.ctx = ctx;
    }

    public HttpRequest getHttpRequest() {
        return httpRequest;
    }

    public void setHttpRequest(HttpRequest httpRequest) {
        this.httpRequest = httpRequest;
    }
}

5、LhResponse

package com.lh.study.rpc.io.tomcat.v1;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;

import static io.netty.handler.codec.http.HttpHeaderNames.*;

/**
 * @description:
 * @author: lianghao
 * @create: 8/6/2019 9:34 AM
 **/
public class LhResponse {

    private ChannelHandlerContext ctx;

    private HttpRequest httpRequest;

    public LhResponse(ChannelHandlerContext ctx, HttpRequest httpRequest) {
        this.ctx = ctx;
        this.httpRequest = httpRequest;
    }

    public void write(String out){
        try {
            if(null == out || out.length()==0){
                return;
            }
            FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(
                    // 设置http版本为1.1
                    HttpVersion.HTTP_1_1,
                    // 设置响应状态码
                    HttpResponseStatus.OK,
                    // 将输出值写出 编码为UTF-8
                    Unpooled.wrappedBuffer(out.getBytes("UTF-8")));
            // 设置连接类型 为 JSON
            fullHttpResponse.headers().set(CONTENT_TYPE, "text/json");
            // 设置请求头长度
            fullHttpResponse.headers().set(CONTENT_LANGUAGE, fullHttpResponse.content().readableBytes());
            // 设置超时时间为5000ms
            fullHttpResponse.headers().set(EXPIRES, 5000);
            ctx.write(fullHttpResponse);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            ctx.flush();
            ctx.close();
        }
    }

    public ChannelHandlerContext getCtx() {
        return ctx;
    }

    public void setCtx(ChannelHandlerContext ctx) {
        this.ctx = ctx;
    }

    public HttpRequest getHttpRequest() {
        return httpRequest;
    }

    public void setHttpRequest(HttpRequest httpRequest) {
        this.httpRequest = httpRequest;
    }
}

6、LhServlet

 

package com.lh.study.rpc.io.tomcat.v1;

/**
 * @description:
 * @author: lianghao
 * @create: 8/6/2019 10:44 AM
 **/
public abstract class LhServlet {

    abstract void doGet(LhRequest request , LhResponse response);
    abstract void doPost(LhRequest request , LhResponse response);
}

7、LhServletImpl

package com.lh.study.rpc.io.tomcat.v1;

import java.util.List;
import java.util.Map;

/**
 * @description:
 * @author: lianghao
 * @create: 8/6/2019 10:45 AM
 **/
public class LhServletImpl extends LhServlet {


    @Override
    public void doGet(LhRequest request, LhResponse response) {
        try {
            // 获取 name 参数 并返回
            Map<String, List<String>> params = request.getParams();
            response.write(params.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(LhRequest request, LhResponse response) {
        doGet(request , response);
    }
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值