手写tomcat

Tomcat是非常流行的Web Server,它还是一个满足Servlet规范的容器。那么想一想,Tomcat和我们的Web应用是什么关系?

从感性上来说,我们一般需要把Web应用打成WAR包部署到Tomcat中,在我们的Web应用中,我们要指明URL被哪个类的哪个方法所处理(不论是原始的Servlet开发,还是现在流行的Spring MVC都必须指明)。
由于我们的Web应用是运行在Tomcat中,那么显然,请求必定是先到达Tomcat的。Tomcat对于请求实际上会进行下面的处理:

第一:提供Socket服务

Tomcat的启动,必然是Socket服务,只不过它支持HTTP协议而已!

这里其实可以扩展思考下,Tomcat既然是基于Socket,那么是基于BIO or NIO or AIO呢?

第二:进行请求的分发

要知道一个Tomcat可以为多个Web应用提供服务,那么很显然,Tomcat可以把URL下发到不同的Web应用。

第三:需要把请求和响应封装成request/response

我们在Web应用这一层,可从来没有封装过request/response的,我们都是直接使用的,这就是因为Tomcat已经为你做好了!

话不多说,先来看一眼工程截图:
在这里插入图片描述

MyRequest

package mytomcat;


import java.io.IOException;
import java.io.InputStream;


/**
 * @author zhoufan
 * @Date 2020/7/31
 */
public class MyRequest {

    private String url;
    private String method;

    public MyRequest(InputStream inputStream) throws IOException {
        String httpReuest = "";
        byte[] httpRequestBytes = new byte[1024];
        int length = 0;
        int read = inputStream.read(httpRequestBytes);
        if ((length = read) > 0) {
            httpReuest = new String(httpRequestBytes, 0, length);
        }
        String httpHead = httpReuest.split("\n")[0];
//        获取请求头里面的url
        url = httpHead.split("\\s")[1];
//        获取请求头里面的请求方式
        method = httpHead.split("\\s")[0];
        System.out.print(this);
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }
}

这里,你可以清楚的看到,我们通过输入流,对HTTP协议进行解析,拿到了HTTP请求头的方法以及URL。

MyResponse

package mytomcat;

import java.io.IOException;
import java.io.OutputStream;

/**
 * @author zhoufan
 * @Date 2020/7/31
 */
public class MyResponse {
    private OutputStream outputStream;

    public MyResponse(OutputStream outputStream) {
        this.outputStream = outputStream;
    }


    public void write(String content) throws IOException {

        StringBuffer httpResponse = new StringBuffer();
        httpResponse.append("HTTP/1.1 200 OK\n")
                .append("Content-Type: text/html\n")
                .append("\r\n")
                .append("<html><body>")
                .append(content)
                .append("</body></html>");
        outputStream.write(httpResponse.toString().getBytes());
        outputStream.close();
    }


}

基于HTTP协议的格式进行输出写入。

MyServlet

package mytomcat;

/**
 * @author zhoufan
 * @Date 2020/7/31
 */
public abstract class MyServlet {

    public abstract void doGet(MyRequest myRequest, MyResponse myResponse);

    public abstract void doPost(MyRequest myRequest, MyResponse myResponse);

    public void service(MyRequest myRequest, MyResponse myResponse) {
//        判断请求方式
        if (myRequest.getMethod().equalsIgnoreCase("POST")) {
            doPost(myRequest, myResponse);
        } else if (myRequest.getMethod().equalsIgnoreCase("GET")) {
            doGet(myRequest, myResponse);
        }
    }


}

MyHello

package mytomcat;

import java.io.IOException;

/**
 * @author zhoufan
 * @Date 2020/7/31
 */
public class MyHello extends MyServlet {
    @Override
    public void doGet(MyRequest myRequest, MyResponse myResponse) {
        try {
            myResponse.write("MyHello................get");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(MyRequest myRequest, MyResponse myResponse) {
        try {
            myResponse.write("MyHello................post");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

MySon

package mytomcat;

import java.io.IOException;

/**
 * @author zhoufan
 * @Date 2020/7/31
 */
public class MySon extends MyServlet {
    @Override
    public void doGet(MyRequest myRequest, MyResponse myResponse) {
        try {
            myResponse.write("mySon....................Get");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(MyRequest myRequest, MyResponse myResponse) {
        try {
            myResponse.write("mySon......................post");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

提供这2个具体的Servlet实现,只是为了后续的测试!

MyTomcat

package mytomcat;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhoufan
 * @Date 2020/7/31
 */
public class MyTomcat extends Thread {
    static Map<String, String> map = new HashMap<>();

    //    加载配置文件,我们在servlet开发中,会在web.xml中通过<servlet></servlet>和<servlet-mapping></servlet-mapping>来进行指定哪个URL交给哪个servlet进行处理。
    static {
        map.put("/myhello", "mytomcat.MyHello");
        map.put("/myson", "mytomcat.MySon");
    }

    @Override
    public void run() {
        ServerSocket serverSocket = null;
        try {
//            socket服务器接受客户端消息
            serverSocket = new ServerSocket(8080);
            System.out.println("MYtomcat is start..........");
            while (true) {
                Socket socket = serverSocket.accept();
                InputStream inputStream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream();
                MyRequest myRequest = new MyRequest(inputStream);
                MyResponse myResponse = new MyResponse(outputStream);
//                请求分发
                dispatch(myRequest, myResponse);
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }


    }


    public void dispatch(MyRequest myRequest, MyResponse myResponse) {
//        通过url获取对应的servlet
        String clazz = map.get(myRequest.getUrl());
        Class<MyServlet> myServletClass = null;
        try {
            if (clazz != null) {
//          通过反射创建servlet对象
                myServletClass = (Class<MyServlet>) Class.forName(clazz);
                MyServlet myServlet = myServletClass.newInstance();
                myServlet.service(myRequest, myResponse);
            } else {
                System.out.println("没有配置url映射的servlet.............................." + myRequest.getUrl());
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }


    }


    public static void main(String[] args) {
        MyTomcat myTomcat = new MyTomcat();
        myTomcat.start();
    }


}

这里,你能够看到Tomcat的处理流程:把URL对应处理的Servlet关系形成,解析HTTP协议,封装请求/响应对象,利用反射实例化具体的Servlet进行处理即可。

最后访问通过url访问
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值