IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> tomcat06-手写简化tomcat(Bio) -> 正文阅读

[Java知识库]tomcat06-手写简化tomcat(Bio)

前言

前面的文章,其实我们说过了。。回忆下
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文件
<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>my-tomcat</artifactId>
    <version>1.0-SNAPSHOT</version>

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


    <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.5.6</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <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请求完成.....

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 11:04:09  更:2022-05-05 11:06:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:56:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码