tomcat06-手写简化tomcat

tomcat06-手写简化tomcat,第1张

前言

前面的文章,其实我们说过了。。回忆下
tomcat官网:https://tomcat.apache.org

The Apache Tomcat® software is an open source implementation of the Java Servlet, 
JavaServer Pages, Java Expression Language and Java WebSocket technologies. 

Tomcat 是使用了Java WebSocket技术和serlet技术,tomcat使用java实现

最核心的两部分connector和container
connector部分,我们用bio的方式,websocket实现
container部分,用servlet集成
我们一步一步的说明

只实现web容器

新建一个maven项目叫my-tomcat

package com.my.tomcat.bio;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;

/**
 * 手写tomcat BIO模式
 */
public class Tomcat {
    private static Logger logger= LoggerFactory.getLogger(Tomcat.class);
    private static Properties pro = new Properties();

    /**
     * 初始化
     */
    public static void init(){
        try {
            FileInputStream fileInputStream = new FileInputStream("src/main/resources/server.properties");
            pro.load(fileInputStream);
            logger.info("init 读取配置完成");
        } catch (FileNotFoundException e) {
            logger.error("初始化server配置文件错误",e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            logger.error("pro加载server报错",e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 启动
     */
    public static void start (){
        //启动web容器
        int port = Integer.parseInt(pro.getProperty("server.port"));
        ServerSocket serverSocket = null;

        try {
            serverSocket = new ServerSocket(port);
            while (true){
                Socket accept = serverSocket.accept();
                logger.info("收到连接请求.....");

                OutputStream outputStream=accept.getOutputStream();
                InputStream inputStream = accept.getInputStream();

                //先不使用servlet容器
                //处理输入
                dealInputStream(inputStream);
                //处理输出
                dealOutStream(outputStream,"success request");
            }
        } catch (IOException e) {
            logger.error("启动tomcat报错",e.getMessage());
            e.printStackTrace();
        }finally {
            if(null !=serverSocket)
            {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 模拟处理输入
     */
    private static void dealInputStream(InputStream inputStream) throws IOException {
        String  httStr = "";
        byte [] contentByte = new byte[1024];
        int length;
        if ((length = inputStream.read(contentByte)) >0){
            httStr = new String(contentByte,0,length);
        }
        logger.info("访问请求内容为:"+httStr);

    }

    /**
     * 模拟处理输出
     */
    private static void dealOutStream(OutputStream outputStream, String outContent) throws IOException {
        String httpResponse =
                "HTTP/1.1 200 OK\n" +
                        "Content-Type: text/html\n" +
                        "\r\n" + outContent;
        outputStream.write(httpResponse.getBytes());
        outputStream.close();
    }

    /**
     * 启动main方法
     * @param args
     */
    public static void main(String[] args) {
        init();
        start();
    }


}

pom.xml文件

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>org.examplegroupId>
    <artifactId>my-tomcatartifactId>
    <version>1.0-SNAPSHOTversion>

    <properties>
        <java.version>1.11java.version>
        <build.sourceEncoding>UTF-8build.sourceEncoding>
    properties>


    <dependencies>
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-apiartifactId>
            <version>1.5.6version>
        dependency>
        <dependency>
            <groupId>ch.qos.logbackgroupId>
            <artifactId>logback-classicartifactId>
            <version>1.2.3version>
        dependency>

    dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-pluginartifactId>
                <configuration>
                    <source>${java.version}source>
                    <target>${java.version}target>
                    <encoding>${build.sourceEncoding}encoding>
                configuration>
            plugin>
        plugins>
    build>

project>
• Server.properties
server.port=8080
• 使用main方法启动
14:38:57.040 [main] INFO com.my.tomcat.bio.Tomcat - init 读取配置完成
• 结果

访问:http://localhost:8080/mytomcat?id=10
看看控制台打印:

14:45:15.590 [main] INFO com.my.tomcat.bio.Tomcat - 收到连接请求.....
14:45:15.612 [main] INFO com.my.tomcat.bio.Tomcat - 访问请求内容为:GET /mytomcat?id=10 HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9

web容器+servlet 代码说明
• init方法中

1、servlet请求接口配置文件,嗯有请求接口配置了,那么得解析呀
2、servlet配置文件初始化并解析,结果放入内存中

• start方法中

先想到了什么呢?
1、请求过来后,是不是得有HttpServletRequest对象,ok,得有一个这个类,doGet,doPost,service方法
2、同样道理,有请求就有输出,得有HttpServletResponse类
3、那配置有了,请求处理有了,返回有了,缺个步骤啊,我怎么知道这个请求交给谁怎么去处理呀,OK,再来一个分发器,就组合起来了,我们一步一步来。。
4、那我们就要写请求的servlet,doGet,doPost,service方法,搞个抽象类呗

代码处理 代码结构

我们按照上面的步骤安排
• init方法中servlet请求接口配置文件

server.port=8080

#servlet配置,不新建文件了

loginServlet.url=com.my.tomcat.bio.servlet.controller.LoginServlet:/login
helloServlet.url=com.my.tomcat.bio.servlet.controller.HelloServlet:/hello

package com.my.tomcat.bio.servlet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;

/**
 * servlet配置解析
 */
public class ServletMappingConfig {
    public static List<ServletMapping> servletMappingList = new ArrayList<>();
    public static Logger logger = LoggerFactory.getLogger(ServletMappingConfig.class);

    public static void initServletMapping(Properties prop) {
        Set<String> strings = prop.stringPropertyNames();
        for (String str : strings) {
            if (str.endsWith(".url")) {
                String servletName = str.replaceAll(".url", "");
                String value[] = prop.getProperty(str).split(":");
                if (null == value || value.length != 2) {
                    logger.error("servlet配置异常--key=" + str + "--value=" + prop.getProperty(str));
                    logger.error("servlet请参考模板格式:servletName.url = ClassName:url");
                    continue;
                }
                ServletMapping servletInfo = new ServletMapping(servletName, value[0], value[1]);
                logger.info("初始化servlet:" + servletInfo.toString());
                servletMappingList.add(servletInfo);
            }
        }
    }
}

package com.my.tomcat.bio.servlet;

/**
 * 解析servlet请求配置后映射的对象
 */
public class ServletMapping {
    private String servletName;
    private String clazz;
    private String url;

    public ServletMapping(String servletName, String clazz, String url) {
        this.servletName = servletName;
        this.clazz = clazz;
        this.url = url;
    }

    @Override
    public String toString() {
        return "ServletMapping{" +
                "servletName='" + servletName + '\'' +
                ", clazz='" + clazz + '\'' +
                ", url='" + url + '\'' +
                '}';
    }

    public String getServletName() {
        return servletName;
    }

    public void setServletName(String servletName) {
        this.servletName = servletName;
    }

    public String getClazz() {
        return clazz;
    }

    public void setClazz(String clazz) {
        this.clazz = clazz;
    }

    public String getUrl() {
        return url;
    }

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

• init方法中servlet配置文件初始化并解析,结果放入内存中

这个在Tomcat类中,最后再看

• start方法中的类
package com.my.tomcat.bio.servlet;

public abstract class Servlet {

    public static  final  String GET="GET";
    public static  final  String PUT="POST";
    public abstract  void doGet(HttpServletRequest request, HttpServletResponse response);

    public abstract  void doPost(HttpServletRequest request, HttpServletResponse response);

    public void service(HttpServletRequest request, HttpServletResponse response)
    {
        if(request == null)
        {
            System.out.println("HttpServletRequest is null");
        }
        if(response == null)
        {
            System.out.println("HttpServletResponse is null");
        }
        if(request.getMethod().equals("GET"))
        {
            doGet(request,response);
        }else if(request.getMethod().equals("POST"))
        {
            doPost(request,response);
        }


    }


}

package com.my.tomcat.bio.servlet;

import com.my.tomcat.bio.Tomcat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

/**
 * servlet请求处理
 */
public class HttpServletRequest  {
    private static Logger logger= LoggerFactory.getLogger(HttpServletRequest.class);
    private  String url;
    private  String method;

    public HttpServletRequest(InputStream inputStream)throws IOException
    {
        String  httStr = "";
        byte [] contentByte = new byte[1024];
        int length;
        if ((length = inputStream.read(contentByte)) >0){
            httStr = new String(contentByte,0,length);
        }
        logger.info("servlet访问请求内容为:"+httStr);
      
	if (!httStr.isEmpty() && !httStr.equals("")) {
	            String httpHead = httStr.split("\n")[0];
	            method = httpHead.split("\s")[0];
	            url = httpHead.split("\s")[1];
	        }
	    }
    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;
    }
}

package com.my.tomcat.bio.servlet;

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

/**
 * servlet response处理
 */
public class HttpServletResponse {
    private OutputStream outputStream;
    public HttpServletResponse(OutputStream outputStream)
    {
        this.outputStream=outputStream;
    }

    public void write(String content) throws IOException {
        String httpResponse =
                "HTTP/1.1 200 OK\n" +
                        "Content-Type: text/html\n" +
                        "servlet响应"+
                        "\r\n" + content;
        outputStream.write(httpResponse.getBytes());
        outputStream.close();
    }
}

• 请求controller servlet的类
package com.my.tomcat.bio.servlet.controller;

import com.my.tomcat.bio.servlet.HttpServletRequest;
import com.my.tomcat.bio.servlet.HttpServletResponse;
import com.my.tomcat.bio.servlet.Servlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * 登录请求controller实现
 */
public class LoginServlet extends Servlet {
    public static Logger logger = LoggerFactory.getLogger(LoginServlet.class);

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        logger.info("get method Login Servlet");
        try {
            response.write("login success");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        logger.info("post method Login Servlet");
        try {
            response.write("login success");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package com.my.tomcat.bio.servlet.controller;

import com.my.tomcat.bio.servlet.HttpServletRequest;
import com.my.tomcat.bio.servlet.HttpServletResponse;
import com.my.tomcat.bio.servlet.Servlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * hello servlet接口实现
 */
public class HelloServlet extends Servlet {

    public static Logger logger = LoggerFactory.getLogger(LoginServlet.class);

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        logger.info("get method Hello Servlet");
        try {
            response.write("Hello success");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        logger.info("post method Hello Servlet");
        try {
            response.write("Hello success");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

• tomcatBio主启动类
package com.my.tomcat.bio;

import com.my.tomcat.bio.servlet.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 手写tomcat BIO模式
 */
public class TomcatBio {
    private static Logger logger = LoggerFactory.getLogger(TomcatBio.class);
    private static Properties pro = new Properties();

    //servlet接口请求池
    private static Map<String, String> servletPool = new ConcurrentHashMap<>();

    /**
     * 初始化
     */
    public static void init() {
        try {
            FileInputStream fileInputStream = new FileInputStream("src/main/resources/server.properties");
            pro.load(fileInputStream);
            logger.info("init 读取配置完成");

            //初始化servlet配置
            ServletMappingConfig.initServletMapping(pro);
            //解析servlet配置,并放入请求池中
            for (ServletMapping servletMapping : ServletMappingConfig.servletMappingList) {
                servletPool.put(servletMapping.getUrl(), servletMapping.getClazz());
            }
            logger.info("init servlet 配置完成");
        } catch (FileNotFoundException e) {
            logger.error("初始化server配置文件错误", e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            logger.error("pro加载server报错", e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 启动
     */
    public static void start() {
        //启动web容器
        int port = Integer.parseInt(pro.getProperty("server.port"));
        ServerSocket serverSocket = null;

        try {
            serverSocket = new ServerSocket(port);
            while (true) {
                Socket accept = serverSocket.accept();
                logger.info("收到连接请求.....");

                OutputStream outputStream = accept.getOutputStream();
                InputStream inputStream = accept.getInputStream();

               /* //先不使用servlet容器
                //只使用web容器 处理输入
                dealInputStream(inputStream);
                //处理输出
                dealOutStream(outputStream,"success request");*/
                //使用servlet容器
                HttpServletRequest httpServletRequest = new HttpServletRequest(inputStream);
                HttpServletResponse httpServletResponse = new HttpServletResponse(outputStream);
                dispatch(httpServletRequest,httpServletResponse);
                logger.info("servlet请求完成.....");
            }
        } catch (IOException e) {
            logger.error("启动tomcat报错", e.getMessage());
            e.printStackTrace();
        } finally {
            if (null != serverSocket) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 模拟处理输入
     */
    private static void dealInputStream(InputStream inputStream) throws IOException {
        String httStr = "";
        byte[] contentByte = new byte[1024];
        int length;
        if ((length = inputStream.read(contentByte)) > 0) {
            httStr = new String(contentByte, 0, length);
        }
        logger.info("访问请求内容为:" + httStr);

    }

    /**
     * 模拟处理输出
     */
    private static void dealOutStream(OutputStream outputStream, String outContent) throws IOException {
        String httpResponse =
                "HTTP/1.1 200 OK\n" +
                        "Content-Type: text/html\n" +
                        "\r\n" + outContent;
        outputStream.write(httpResponse.getBytes());
        outputStream.close();
    }

    /**
     * servlet分发器
     * @param request 请求request
     * @param response 请求response
     */
    public static void dispatch(HttpServletRequest request, HttpServletResponse response) {
        if (!servletPool.containsKey(request.getUrl())) {
            logger.error("servlet分发器未找到对应的servlet的配置");
            try {
                String httpResponse =
                        "HTTP/1.1 200 OK\n" +
                                "Content-Type: text/html\n" +
                                "\r\n" + "404 Exception";
                response.write(httpResponse);
                return;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        String className = servletPool.get(request.getUrl());
        try {
            Class<Servlet> clazz = (Class<Servlet>) Class.forName(className);
            Servlet servlet = clazz.newInstance();
            servlet.service(request, response);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }


    /**
     * 启动main方法
     *
     * @param args
     */
    public static void main(String[] args) {
        init();
        start();
    }


}

验证

启动TomcatBio.java–>main()

17:45:27.718 [main] INFO com.my.tomcat.bio.TomcatBio - init 读取配置完成
17:45:27.774 [main] INFO com.my.tomcat.bio.servlet.ServletMappingConfig - 初始化servlet:ServletMapping{servletName='helloServlet', clazz='com.my.tomcat.bio.servlet.controller.HelloServlet', url='/hello'}
17:45:27.774 [main] INFO com.my.tomcat.bio.servlet.ServletMappingConfig - 初始化servlet:ServletMapping{servletName='loginServlet', clazz='com.my.tomcat.bio.servlet.controller.LoginServlet', url='/login'}
17:45:27.774 [main] INFO com.my.tomcat.bio.TomcatBio - init servlet 配置完成

访问:http://localhost:8080/mytomcat?id=10
结果:

访问:http://localhost:8080/login
http://localhost:8080/hello

17:57:07.546 [main] INFO com.my.tomcat.bio.servlet.controller.LoginServlet - get method Login Servlet
17:57:07.548 [main] INFO com.my.tomcat.bio.TomcatBio - servlet请求完成.....
17:57:07.548 [main] INFO com.my.tomcat.bio.TomcatBio - 收到连接请求.....


17:57:12.447 [main] INFO com.my.tomcat.bio.servlet.controller.LoginServlet - get method Hello Servlet
17:57:12.448 [main] INFO com.my.tomcat.bio.TomcatBio - servlet请求完成.....

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/872164.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存