Tomcat程式碼實現

HowieLee59發表於2018-11-08

最近開課學到了Tomcat,對這個挺感興趣,就跟著網上的教程自己實現了一遍。

眾所周知,Tomcat是一個滿足Servlet規範的容器,在Java Web的專案中大量使用;一般來說,我們需要將Web應用打包成War檔案部署到Tomcat伺服器中,通過制定對映關係來制定路徑,指明被哪個方法處理。Tomcat對於實際的請求會做出以下的操作:

  • 提供Socket服務,不過是支援HTTP的Socket
  • 進行請求的下發
  • 將請求與響應封裝成response和request

下面上程式碼:

一.封裝請求物件

import java.io.IOException;
import java.io.InputStream;
//封裝請求物件,通過輸入流,對 HTTP 協議進行解析,拿到 HTTP 請求頭的方法以及 URl
public class MyRequest {
	private String url;
	private String method;
	public MyRequest(InputStream inputStream) throws IOException {
    	String httpRequest = " ";
    	byte[] httpRequestBytes = new byte[1024];
   		int length;
    	if ((length = inputStream.read(httpRequestBytes)) > 0) {
        	httpRequest = new String(httpRequestBytes, 0, length);
    	}
    	String httpHead = httpRequest.split("\n")[0];
    	url = httpHead.split("\\s")[1];
    	method = httpHead.split("\\s")[0];
 	}
	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;
	}
}
//通過Socket中的輸入輸出流,進行對網址的解析,分別將url和method進行分離。

二.封裝響應物件

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

//封裝響應物件,基於HTTP協議的格式進行輸出
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協議格式進行寫入操作

三.Servlet請求處理基類

import java.io.IOException;

public class MyServlet  {
    public void doGet(MyRequest myRequest,MyResponse myResponse){
        try{
            myResponse.write(" get Hello World");
        }catch (IOException e){
            e.printStackTrace();
        }
    }

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

  public  void service(MyRequest myRequest,MyResponse myResponse){
          if(myRequest.getMethod().equalsIgnoreCase("post")){
            doPost(myRequest,myResponse);
          }else if(myRequest.getMethod().equalsIgnoreCase("get")){
              doGet(myRequest,myResponse);
          }
  }
}
//Tomcat提供doPost(),doGet(),service()方法

四.Servletp配置

public class ServletMapping {
    private String servletName;
    private String url;
    private String clazz;

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

    public String getServletName() {
        return servletName;
    }

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

    public String getUrl() {
        return url;
    }

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

    public String getClazz() {
        return clazz;
    }

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

import java.util.ArrayList;
import java.util.List;

public class ServletMappingConfig {
    public static List<ServletMapping> servletMappingList = new ArrayList<>();
    static {
        servletMappingList.add(new ServletMapping("Hello World","/world","MyServlet"));
    }
}
//通過設定對映關係對方法進行map對映呼叫。

五.啟動類

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

//tomcat服務的啟動類
public class MyTomcat {
    private int port ;
    private Map<String,String> urlServletMap = new HashMap<>();

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

    public MyTomcat(int port){
        this.port = port;
    }

    public void start(){
        //初始化 URL與對應處理的servlet的關係
        initServletMapping();

        ServerSocket serverSocket = null;

        try{
            serverSocket = new ServerSocket(port);
            System.out.println("MyTomcat is start on " + port);

            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();
                }
            }
        }
    }

    //初始化url 與對應servler的關係
    private void initServletMapping(){
        for(ServletMapping servletMapping : ServletMappingConfig.servletMappingList){
            urlServletMap.put(servletMapping.getUrl(),servletMapping.getClazz());
        }
    }

    //請求分發
    private void dispatch(MyRequest myRequest,MyResponse myResponse){
           String clazz = urlServletMap.get(myRequest.getUrl());

           //利用反射例項化具體的servlet處理請求
           try{
               Class<MyServlet> myServletClass =(Class<MyServlet>) Class.forName(clazz);
               MyServlet myServlet = myServletClass.newInstance();
               myServlet.service(myRequest,myResponse);
           }catch (ClassNotFoundException e){
              e.printStackTrace();
           }catch (InstantiationException e){
              e.printStackTrace();
           }catch (IllegalAccessException e){
              e.printStackTrace();
           }
    }
}
//解析HTTP協議,封裝請求/響應物件,使用反射的例項化進行對映。

相關文章