第五章 手写Tomcat笔记

一、什么是Tomcat

Tomcat本质上是一款开源轻量级Web应用服务器,是一款优秀的Servlet容器实现。

核心2点,Web服务器、Servlet容器。

阿里中间件团队:http://jm.taobao.org/about/

很多公司都手写或者重写Tomcat.比如aliTomcat :    https://help.aliyun.com/document_detail/90754.html

1、网络基础知识

网络通讯,客户端和服务端的关系,java中建立Socket通讯,注意一般Socket是基于TCP的协议。

第五章 手写Tomcat笔记_第1张图片

 

2、还原Tomcat本质

第五章 手写Tomcat笔记_第2张图片

 

二、手写Tomcat实现代码

1、手写第一步:完成简单的一个BIO的通讯

//1、绑定端口 ---JDK 为我们提供的网络操作的API
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("服务器启动成功!");
while(!serverSocket.isClosed()){//在等待请求
    //2、有请求过来了  ,使用一个socket: 代表着一个客户端--服务端的连接
   Socket socket =  serverSocket.accept();
   //3、使用一个线程来处理请求
    executorService.execute(()->{
        try{
            InputStream inputStream = socket.getInputStream();
            System.out.println("收到请求:");
            BufferedReader reader = new BufferedReader( new InputStreamReader(inputStream,"utf-8"));
            //字符串
            String msg =null;
            StringBuilder requestInfo = new StringBuilder();
            while ( (msg=reader.readLine()) !=null ){
                if(msg.length()==0) break;
                requestInfo.append(msg).append("\r\n");
            }
            System.out.println(requestInfo);
            //要对请求的头进行解析,获取请求的第一行
            String firstline =requestInfo.toString().split("\r\n")[0];
            System.out.println(firstline);

2、Tomcat如何和浏览器互动

浏览器之间通讯必须要符合HTTP协议,响应信息加入HTTP格式的响应

//要对请求的头进行解析,获取请求的第一行
    String firstline =requestInfo.toString().split("\r\n")[0];
    System.out.println(firstline);
    //防止浏览器发空过的请求过来
    if(firstline.length()<1){
        return;
    }
    String servletPath = firstline.split(" ")[1];
    //Servet映射
    Map servletMapping=  (Map)webAppMap.get("servlet-mapping");
    //Servlet实例
    Map servletInstances=  (Map )webAppMap.get("servlet");
    //是否有正确的url对应的Servlet
    if(servletMapping.containsKey(servletPath)){
        String servletName = servletMapping.get(servletPath);
        HttpServlet httpServlet =  (HttpServlet)servletInstances.get(servletName);
        HttpServletRequest httpServletRequest =createRequest();
        HttpServletResponse httpServletResponse = createResponse();
        httpServlet.service(httpServletRequest,httpServletResponse);
        OutputStream outputStream = socket.getOutputStream();
        byte[] response ="请求成功!".getBytes();
        outputStream.write("HTTP/1.1 200 OK \r\n".getBytes());
        outputStream.write("Content-Type:text/html;charset=utf-8 \r\n".getBytes());
        outputStream.write( ("Content-Length:"+response.length+"\r\n").getBytes());
        outputStream.write("\r\n".getBytes());
        outputStream.write(response);
        outputStream.flush();
        System.out.println("----END");
    }else{
        //要与浏览器进行“互动” ,HTTP 协议
        OutputStream outputStream = socket.getOutputStream();
        byte[] response ="对不起,没有对应的Servlet请求信息!".getBytes();
        outputStream.write("HTTP/1.1 200 OK \r\n".getBytes());
        outputStream.write("Content-Type:text/html;charset=utf-8 \r\n".getBytes());
        outputStream.write( ("Content-Length:"+response.length+"\r\n").getBytes());
        outputStream.write("\r\n".getBytes());
        outputStream.write(response);
        outputStream.flush();
        System.out.println("----END");
    }
}catch (IOException e){

3、让代码在Tomcat上跑

类加载

public static void main(String[] args) throws  Exception{
    //0、加载项目(类加载)、容器、HashMap
    Map webAppMap = ProjectLoader.load();



public class ProjectLoader {
    public static Map load() throws Exception{
        //定义一个Map,存储项目信息
        Map webapp = new HashMap<>();
        Map servletInstances = new HashMap<>(); //servlet
        Map servletMapping = new HashMap<>(); //servlet-mapping
        //项目路径
        String webappPath ="D:\\work_public\\servletdemo\\out\\artifacts\\servletdemo_war_exploded\\WEB-INF";
        //JDK提供类加载器 URL
        URL classFile = new URL("file:"+webappPath+"\\classes\\");
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{classFile});
        //解析xml文件
        //1.获取解析器
        SAXReader reader = new SAXReader();
        //2.获取文档对象(xml)
        Document document = reader.read(new File(webappPath+"\\web.xml"));
        //3.获取根元素
        Element root = document.getRootElement();
        //4.获取根元素中下的子元素
        List childElements = root.elements();
        //5.遍历子元素
        for (Element element:childElements) {
            //6.判断元素名称为servlet的元素
            if ("servlet".equals(element.getName())) {
                //获取servlet-name元素
                Element servletName = element.element("servlet-name");
                //获取servlet-class元素
                Element servletClass = element.element("servlet-class");
                String strServletName = servletName.getText();
                String strServletClass = servletClass.getText();
                System.out.println("servlet:"+strServletName+"="+strServletClass);
                //1.加载到JVM
                Class classzz= urlClassLoader.loadClass(strServletClass);
                //2 创建对象实例(反射) -servlet;
                Servlet servlet  = (Servlet)classzz.newInstance();
                //web.xml的servlet实例化放入hashmap
                servletInstances.put(strServletName, servlet);
            }
            //7.判断元素名称为servlet-mapping的元素
            if ("servlet-mapping".equals(element.getName())) {
                //获取servlet-name元素
                Element servletName = element.element("servlet-name");
                //获取url-pattern元素
                Element urlPattern = element.element("url-pattern");
                String strServletName = servletName.getText();
                String strUrlPattern = urlPattern.getText();
                //web.xml的servlet的Mapping放入hashmap
                System.out.println("servlet-mapping:"+strUrlPattern+"="+strServletName);
                servletMapping.put(strUrlPattern,strServletName);
            }
        }
        webapp.put("servlet",servletInstances);
        webapp.put("servlet-mapping",servletMapping);
        return  webapp;
    }
}

解析请求地址,找到对应的Servlet

//要对请求的头进行解析,获取请求的第一行
String firstline =requestInfo.toString().split("\r\n")[0];
System.out.println(firstline);
//防止浏览器发空过的请求过来
if(firstline.length()<1){
    return;
}
String servletPath = firstline.split(" ")[1];
//Servet映射
Map servletMapping=  (Map)webAppMap.get("servlet-mapping");
//Servlet实例
Map servletInstances=  (Map )webAppMap.get("servlet");

4、构造参数,执行Servlet的service方法

//是否有正确的url对应的Servlet
if(servletMapping.containsKey(servletPath)){
    String servletName = servletMapping.get(servletPath);
    HttpServlet httpServlet =  (HttpServlet)servletInstances.get(servletName);
    HttpServletRequest httpServletRequest =createRequest();
    HttpServletResponse httpServletResponse = createResponse();
    httpServlet.service(httpServletRequest,httpServletResponse);
    OutputStream outputStream = socket.getOutputStream();
    byte[] response ="请求成功!".getBytes();
    outputStream.write("HTTP/1.1 200 OK \r\n".getBytes());
    outputStream.write("Content-Type:text/html;charset=utf-8 \r\n".getBytes());
    outputStream.write( ("Content-Length:"+response.length+"\r\n").getBytes());
    outputStream.write("\r\n".getBytes());
    outputStream.write(response);
    outputStream.flush();
    System.out.println("----END");

构建简单的参数

HttpServletRequest httpServletRequest =createRequest();
HttpServletResponse httpServletResponse = createResponse();

你可能感兴趣的:(Tomcat架构)