欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于netty实现的迷你版TOMCat

程序员文章站 2022-05-13 21:38:35
...

1.首先有一个tomcat类用来管理网络请求和servlet映射

package com.tomcatmini;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
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.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;

import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * Created by chenli on 2019/11/11.
 */
public class MiNiTomcat {

    private int port=8080;//端口
    private Map<String,MiNiServlet> map=new HashMap<>();
    private Properties webxml=new Properties();
    private void init(){
        //加载xml文件
        try{
            String WEB_INF=this.getClass().getResource("/").getPath();
            FileInputStream fis=new FileInputStream(WEB_INF+"webxml.properties");
            //基于properties实现
            webxml.load(fis);
            for (Object k:webxml.keySet()){
                String key=k.toString();
                if (key.endsWith(".url")){
                    String servletName = key.replaceAll("\\.url$", "");
                    String url = webxml.getProperty(key);
                    String className = webxml.getProperty(servletName + ".className");
                    MiNiServlet obj = (MiNiServlet)Class.forName(className).newInstance();
                    map.put(url, obj);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void start() throws InterruptedException {
        EventLoopGroup bossGroup=null;
        EventLoopGroup workGroup=null;
        try {
            init();
            //Netty 封装了NIO reator
            //主线程
             bossGroup = new NioEventLoopGroup();
            //工作线程
             workGroup = new NioEventLoopGroup();

            //
            ServerBootstrap server = new ServerBootstrap();

            server.group(bossGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    //子线程调用
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel client) throws Exception {
                            //客户端初始化处理
                            // 无锁化串行编程
                            //Netty对HTTP协议的封装,顺序有要求
                            //HttpResponseEncoder 编码器
                            client.pipeline().addLast(new HttpResponseEncoder());
                            //HttpRequestDecoder解码器
                            client.pipeline().addLast(new HttpRequestDecoder());
                            //业务逻辑处理
                            client.pipeline().addLast(new MiNiTomcatHander());
                        }
                    })
                    //针对于主线程分配最大线程数量 --128
                    .option(ChannelOption.SO_BACKLOG, 128)
                    //针对于子线程配置
                    .childOption(ChannelOption.SO_KEEPALIVE, true);


            //启动服务
            ChannelFuture future = server.bind(port).sync();

            System.out.println("MiNi tomcat start " + port);
            //关闭服务
            future.channel().closeFuture().sync();

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new MiNiTomcat().start();
    }

    private class MiNiTomcatHander extends ChannelInboundHandlerAdapter {


        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            if (msg instanceof HttpRequest){
                HttpRequest req=(HttpRequest) msg;

                //转交给自己实现的请求
                MiNiRequest request=new MiNiRequest(ctx,req);

                //自己实现
                MiNiResponse response=new MiNiResponse(ctx,req);

                String url=request.getUrl();

                if (map.containsKey(url)){
                    map.get(url).service(request,response);
                }else {
                    response.write("404 not fund url");
                }
            }
        }
    }
}

2.封装请求类

package com.tomcatmini;

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

/**
 * Created by chenli on 2019/11/12.
 */
public class MiNiRequest {
    ChannelHandlerContext ctx;
    HttpRequest req;


    public MiNiRequest(ChannelHandlerContext ctx, HttpRequest req) {
        this.ctx=ctx;
        this.req=req;
    }

    public String getUrl() {
        return req.getUri();
    }

    public String getMethod() {
        return req.getMethod().name();
    }
}

3.封装响应类

package com.tomcatmini;

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

import java.io.UnsupportedEncodingException;

/**
 * Created by chenli on 2019/11/12.
 */
public class MiNiResponse {
    //SocketChannel的封装
    private ChannelHandlerContext ctx;

    private HttpRequest req;
    public MiNiResponse(ChannelHandlerContext ctx, HttpRequest req) {
        this.ctx=ctx;
        this.req=req;
    }

    public void write(String out) {
        if (out == null || out.length()==0){
            return;
        }
        try {
            FullHttpResponse fullHttpResponse=new DefaultFullHttpResponse(
                    HttpVersion.HTTP_1_1,
                    HttpResponseStatus.OK,
                    // 将输出值写出 编码为UTF-8
                    Unpooled.wrappedBuffer(out.getBytes("UTF-8")));
            fullHttpResponse.headers().set("Content-Type", "text/html;");
            ctx.write(fullHttpResponse);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }finally {
            ctx.flush();
            ctx.close();

        }
    }
}

4.抽象servlet

package com.tomcatmini;

/**
 * Created by chenli on 2019/11/11.
 */
public abstract class MiNiServlet {
    public void service(MiNiRequest request, MiNiResponse response) {
        if ("GET".equalsIgnoreCase(request.getMethod())){
            doGet(request,response);
        }else{
            doPost(request,response);
        }
    }

    protected abstract void doPost(MiNiRequest request, MiNiResponse response);

    protected abstract void doGet(MiNiRequest request, MiNiResponse response);
}

5.第一个servlet

package com.tomcatmini;

/**
 * Created by chenli on 2019/11/13.
 */
public class FirstServlet extends MiNiServlet {
    @Override
    protected void doPost(MiNiRequest request, MiNiResponse response) {
        this.doPost(request,response);
    }

    @Override
    protected void doGet(MiNiRequest request, MiNiResponse response) {
        response.write("FirstServlet alreadly start !");
    }
}

6.第二个servlet

package com.tomcatmini;

/**
 * Created by chenli on 2019/11/13.
 */
public class SecondServlet extends MiNiServlet {
    @Override
    protected void doPost(MiNiRequest request, MiNiResponse response) {
        System.out.println("第二个servlet");
    }

    @Override
    protected void doGet(MiNiRequest request, MiNiResponse response) {
        this.doPost(request,response);
    }
}

7.配置文件

servlet.one.url=/firstServlet.do
servlet.one.className=com.tomcatmini.FirstServlet

servlet.two.url=/secondServlet.do
servlet.two.className=com.tomcatmini.SecondServlet