手写一个简化版的Tomcat(BIO版本)

一、摘要:

序号 实现方式 功能链接
1 BIO 手写一个简化版的Tomcat(BIO版本)
2 BIO-Plus 手写一个简化版的Tomcat(BIO升级版本)
3 NIO 手写一个简化版的Tomcat(NIO版本)
4 Netty 手写一个简化版的Tomcat(Netty版本)

二、demo编码

package com.jason.http.server.bio;
import com.jason.http.server.support.servlet.ServletMapping;
import com.jason.http.server.support.servlet.ServletMappingConfig;
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;

import static java.lang.Thread.sleep;

public class Tomcat {
    private static Logger logger= LoggerFactory.getLogger(Tomcat.class);
    private static Properties prop=new Properties();

    private static Map<String,String> servletPool=new ConcurrentHashMap<>();

    public static void  start()
    {
        int port=Integer.parseInt(prop.getProperty("server.port"));
        logger.info("start tomcat finished , listen port at"+port);
        logger.info("waiting request");
        ServerSocket  serverSocket=null;
        try {
            serverSocket=new ServerSocket(port);
            while(true)
            {
                Socket accept = serverSocket.accept();
                logger.info("收到连接请求.....");
                try {
                    sleep(10000);//测试阻塞10秒,是否还可以响应其他请求,浏览器端观察效果
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                InputStream inputStream=accept.getInputStream();
                OutputStream outputStream=accept.getOutputStream();
                HttpServletRequest request=new HttpServletRequest(inputStream);
                HttpServletResponse response=new HttpServletResponse(outputStream);
                dispatch(request,response);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
             if(null !=serverSocket)
             {
                 try {
                     serverSocket.close();
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             }
        }

    }
    public static void init() throws  Exception
    {
        FileInputStream  fin=new FileInputStream("F:\\workspace\\netty\\tomcat\\src\\main\\resources\\web-bio.properties");
        prop.load(fin);
        logger.info("读取配置");
        ServletMappingConfig.initServletMapping(prop);

        //解析servlet配置
        for(ServletMapping servletMapping: ServletMappingConfig.servletMappingList)
        {
            servletPool.put(servletMapping.getUrl(),servletMapping.getClazz());
        }
    }
    public static void dispatch(HttpServletRequest request, HttpServletResponse response)
    {
        if(!servletPool.containsKey(request.getUrl()))
        {
            logger.error("未找到对应的servlet的配置");
            try {
                response.write("404 Exception");
                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();
        }
    }

    public static void main(String[] args) {
        try{
            init();
            start();
        }catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}
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);
        }


    }


}

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

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" +
                            "\r\n" + content;
                  outputStream.write(httpResponse.getBytes());
                  outputStream.close();



      }
    }


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

public class HttpServletRequest  {
    private  String url;
    private  String method;

    public HttpServletRequest(InputStream inputStream)throws IOException
    {
          String httpRequestStr="";
          byte[] requestContent=new byte[1024];
          int length;
          if((length=inputStream.read(requestContent))>0)
          {
              httpRequestStr=new String(requestContent,0,length);
          }
          System.out.println(httpRequestStr);
          String httpHead = httpRequestStr.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;
    }
}

三、测试程序:

import com.jason.http.server.bio.HttpServletRequest;
import com.jason.http.server.bio.HttpServletResponse;
import com.jason.http.server.bio.Servlet;


import java.io.IOException;

public class HelloServlet extends Servlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("hello servlet");
        try {
            response.write("say hello world");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("hello servlet");
        try {
            response.write("say hello world");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

import com.jason.http.server.bio.HttpServletRequest;
import com.jason.http.server.bio.HttpServletResponse;
import com.jason.http.server.bio.Servlet;


import java.io.IOException;

public class LoginServlet extends Servlet {

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("Login Servlet");
        try {
            response.write("login success");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("Login Servlet");
        try {
            response.write("login success");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

四、配置文件:

   1、web-bio.properties

server.port=8089
#格式:servletName.url=ClassName:url

loginServlet.url=com.jason.http.server.bio.demo.servlet.LoginServlet:/login
helloServlet.url=com.jason.http.server.bio.demo.servlet.HelloServlet:/hello

  2、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>com.jason.http</groupId>
  <artifactId>tomcat</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>tomcat</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.7.25</version>
    </dependency>
    <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-all</artifactId>
      <version>4.1.50.Final</version>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

 

上一篇:Spring MVC-拦截器


下一篇:使用过滤器解决全栈乱码问题