成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

實現(xiàn)簡單的Tomcat | Tomcat原理學習(1)

Corwien / 1652人閱讀

摘要:項目結(jié)構(gòu)項目結(jié)構(gòu)如下實現(xiàn)細節(jié)創(chuàng)建對象首先創(chuàng)建自定義的請求類,其中定義與兩個屬性,表示請求的以及請求的方式。其構(gòu)造函數(shù)需要傳入一個輸入流,該輸入流通過客戶端的套接字對象得到。創(chuàng)建服務端套接字,并綁定某個端口。

緣起

用了那么久tomcat,突然覺得自己對它或許并沒有想象中的那么熟悉,所以趁著放假我研究了一下這只小貓咪,實現(xiàn)了自己的小tomcat,寫出這篇文章同大家一起分享!

照例附上github鏈接。


項目結(jié)構(gòu)

項目結(jié)構(gòu)如下:



實現(xiàn)細節(jié) 創(chuàng)建MyRequest對象

首先創(chuàng)建自定義的請求類,其中定義url與method兩個屬性,表示請求的url以及請求的方式。

其構(gòu)造函數(shù)需要傳入一個輸入流,該輸入流通過客戶端的套接字對象得到。

輸入流中的內(nèi)容為瀏覽器傳入的http請求頭,格式如下:

GET /student HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: Hm_lvt_eaa22075ffedfde4dc734cdbc709273d=1549006558; _ga=GA1.1.777543965.1549006558

通過對以上內(nèi)容的分割與截取,我們可以得到該請求的url以及請求的方式。

package tomcat.dome;

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

//實現(xiàn)自己的請求類
public class MyRequest {
    //請求的url
    private String url;
    //請求的方法類型
    private String method;
    
    //構(gòu)造函數(shù) 傳入一個輸入流
    public MyRequest(InputStream inputStream) throws IOException {
        //用于存放http請求內(nèi)容的容器
        StringBuilder httpRequest=new StringBuilder();
        //用于從輸入流中讀取數(shù)據(jù)的字節(jié)數(shù)組
        byte[]httpRequestByte=new byte[1024];
        int length=0;
        //將輸入流中的內(nèi)容讀到字節(jié)數(shù)組中,并且對長度進行判斷
        if((length=inputStream.read(httpRequestByte))>0) {
            //證明輸入流中有內(nèi)容,則將字節(jié)數(shù)組添加到容器中
            httpRequest.append(new String(httpRequestByte,0,length));
        }
        //將容器中的內(nèi)容打印出來
        System.out.println("httpRequest = [ "+httpRequest+" ]");
        
        
        //從httpRequest中獲取url,method存儲到myRequest中
        String httpHead=httpRequest.toString().split("
")[0];
        url=httpHead.split("s")[1];
        method=httpHead.split("s")[0];
        System.out.println("MyRequests = [ "+this+" ]");
    }

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



創(chuàng)建MyResponse對象

創(chuàng)建自定義的響應類,構(gòu)造函數(shù)需要傳入由客戶端的套接字獲取的輸出流。

定義其write方法,像瀏覽器寫出一個響應頭,并且包含我們要寫出的內(nèi)容content。

package tomcat.dome;

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

//實現(xiàn)自己的響應類
public class MyResponse {
    //定義輸出流
    private OutputStream outputStream;
    
    //構(gòu)造函數(shù) 傳入輸出流
    public MyResponse(OutputStream outputStream) {
        this.outputStream=outputStream;
    }
    
    //創(chuàng)建寫出方法
    public void write(String content)throws IOException{
        //用來存放要寫出數(shù)據(jù)的容器
        StringBuffer stringBuffer=new StringBuffer();
        stringBuffer.append("HTTP/1.1 200 OK
")
        .append("Content-type:text/html
")
        .append("
")
        .append("Hello World")
        .append(content)
        .append("");
        
        //轉(zhuǎn)換成字節(jié)數(shù)組 并進行寫出
        outputStream.write(stringBuffer.toString().getBytes());
        //System.out.println("sss");
        outputStream.close();
    }
    
}



創(chuàng)建MyServlet對象

由于我們自己寫一個Servlet的時候需要繼承HttpServlet,因此在這里首先定義了一個抽象類——MyServlet對象。

在其中定義了兩個需要子類實現(xiàn)的抽象方法doGet和doSet。

并且創(chuàng)建了一個service方法,通過對傳入的request對象的請求方式進行判斷,確定調(diào)用的是doGet方法或是doPost方法。

package tomcat.dome;

//寫一個抽象類作為servlet的父類
public abstract class MyServlet {
    //需要子類實現(xiàn)的抽象方法
    protected abstract void doGet(MyRequest request,MyResponse response);
    protected abstract void doPost(MyRequest request,MyResponse response);
    
    //父類自己的方法
    //父類的service方法對傳入的request以及response
    //的方法類型進行判斷,由此調(diào)用doGet或doPost方法
    public void service(MyRequest request,MyResponse response) throws NoSuchMethodException {
        if(request.getMethod().equalsIgnoreCase("POST")) {
            doPost(request, response);
        }else if(request.getMethod().equalsIgnoreCase("GET")) {
            doGet(request, response);
        }else {
            throw new NoSuchMethodException("not support");
        }
    }
}



創(chuàng)建業(yè)務相關(guān)的Servlet

這里我創(chuàng)建了兩個業(yè)務相關(guān)類:StudentServlet和TeacherServlet。

package tomcat.dome;

import java.io.IOException;

//實現(xiàn)自己業(yè)務相關(guān)的Servlet
public class StudentServlet extends MyServlet{

    @Override
    protected void doGet(MyRequest request, MyResponse response) {
        //利用response中的輸出流 寫出內(nèi)容
        try {
            //System.out.println("!!!!!!!!!!!!!!!!!!");
            response.write("I am a student.");
            //System.out.println("9999999999999999");
        }catch(IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void doPost(MyRequest request, MyResponse response) {
        //利用response中的輸出流 寫出內(nèi)容
        try {
            response.write("I am a student.");
        }catch(IOException e) {
            e.printStackTrace();
        }    
    }

}
package tomcat.dome;

import java.io.IOException;

//實現(xiàn)自己業(yè)務相關(guān)的Servlet
public class TeacherServlet extends MyServlet{

    @Override
    protected void doGet(MyRequest request, MyResponse response) {
        //利用response中的輸出流 寫出內(nèi)容
        try {
            response.write("I am a teacher.");
        }catch(IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void doPost(MyRequest request, MyResponse response) {
        //利用response中的輸出流 寫出內(nèi)容
        try {
            response.write("I am a teacher.");
        }catch(IOException e) {
            e.printStackTrace();
        }    
    }

}



創(chuàng)建映射關(guān)系結(jié)構(gòu)ServletMapping

該結(jié)構(gòu)實現(xiàn)的是請求的url與具體的Servlet之間的關(guān)系映射。

package tomcat.dome;

//請求url與項目中的servlet的映射關(guān)系
public class ServletMapping {
    //servlet的名字
    private String servletName;
    //請求的url
    private String url;
    //servlet類
    private String 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;
    }
    public ServletMapping(String servletName, String url, String clazz) {
        super();
        this.servletName = servletName;
        this.url = url;
        this.clazz = clazz;
    }
}



映射關(guān)系配置對象ServletMappingConfig

配置類中定義了一個列表,里面存儲著項目中的映射關(guān)系。

package tomcat.dome;

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

//創(chuàng)建一個存儲有請求路徑與servlet的對應關(guān)系的 映射關(guān)系配置類
public class ServletMappingConfig {
    //使用一個list類型 里面存儲的是映射關(guān)系類Mapping
    public static ListservletMappings=new ArrayList<>(16);
    
    //向其中添加映射關(guān)系
    static {
        servletMappings.add(new ServletMapping("student","/student", "tomcat.dome.StudentServlet"));
        servletMappings.add(new ServletMapping("teacher","/teacher", "tomcat.dome.TeacherServlet"));
    }
}



主角登場 MyTomcat!

在服務端MyTomcat中主要做了如下幾件事情:

1)初始化請求的映射關(guān)系。

2)創(chuàng)建服務端套接字,并綁定某個端口。

3)進入循環(huán),用戶接受客戶端的鏈接。

4)通過客戶端套接字創(chuàng)建request與response對象。

5)根據(jù)request對象的請求方式調(diào)用相應的方法。

6)啟動MyTomcat!

package tomcat.dome;

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


//Tomcat服務器類 編寫對請求做分發(fā)處理的相關(guān)邏輯
public class MyTomcat {
    //端口號
    private int port=8080;
    //用于存放請求路徑與對應的servlet類的請求映射關(guān)系的map
    //相應的信息從配置類中獲取
    private MapurlServletMap=new HashMap<>(16);
    //構(gòu)造方法
    public MyTomcat(int port) {
        this.port=port;
    }
    
    //tomcat服務器的啟動方法
    public void start() {
        //初始化請求映射關(guān)系
        initServletMapping();
        //服務端的套接字
        ServerSocket serverSocket=null;
        try {
            //創(chuàng)建綁定到某個端口的服務端套接字
            serverSocket=new ServerSocket(port);
            System.out.println("MyTomcat begin start...");
            //循環(huán) 用于接收客戶端
            while(true) {
                //接收到的客戶端的套接字
                Socket socket=serverSocket.accept();
                //獲取客戶端的輸入輸出流
                InputStream inputStream=socket.getInputStream();
                OutputStream outputStream=socket.getOutputStream();
                //通過輸入輸出流創(chuàng)建請求與響應對象
                MyRequest request=new MyRequest(inputStream);
                MyResponse response=new MyResponse(outputStream);
                
                //根據(jù)請求對象的method分發(fā)請求 調(diào)用相應的方法
                dispatch(request, response);
                //關(guān)閉客戶端套接字
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    //初始化請求映射關(guān)系,相關(guān)信息從配置類中獲取
    private void initServletMapping() {
        for(ServletMapping servletMapping:ServletMappingConfig.servletMappings) {
            urlServletMap.put(servletMapping.getUrl(), servletMapping.getClazz());
        }
    }
    
    //通過當前的request以及response對象分發(fā)請求
    private void dispatch(MyRequest request,MyResponse response) {
        //根據(jù)請求的url獲取對應的servlet類的string
        String clazz=urlServletMap.get(request.getUrl());
        //System.out.println("====="+clazz);
        try {
            //通過類的string將其轉(zhuǎn)化為對象
            Class servletClass=Class.forName("tomcat.dome.StudentServlet");
            //實例化一個對象
            MyServlet myServlet=(MyServlet)servletClass.newInstance();
            
            //調(diào)用父類方法,根據(jù)request的method對調(diào)用方法進行判斷
            //完成對myServlet中doGet與doPost方法的調(diào)用
            myServlet.service(request, response);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
    
    //main方法  直接啟動tomcat服務器
    public static void main(String[] args) {
        new MyTomcat(8080).start();
    }
    
}



測試結(jié)果

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/73638.html

相關(guān)文章

  • Tomcat】IDEA下跟蹤查看源碼

    摘要:算是心血來潮吧,想看看的源碼,順便學習一下。這里就簡單的做點記錄如何用跟蹤查看源碼。當然這里也提供書籍的源碼,可以下載下來對照書看。附上一張運行成功的結(jié)果圖   算是心血來潮吧,想看看 Tomcat 的源碼,順便學習一下。  這里就簡單的做點記錄--如何用 IDEA 跟蹤查看 Tomcat 源碼。  同時,這里也推薦下 how-tomcat-works 這本書,雖然書中講的是 tomc...

    edgardeng 評論0 收藏0
  • tomcat與nginx反向代理,https過程分析

    摘要:接下來我們要配置這個的端口,這樣他們才能運行時端口號不沖突。問題指明不同的端口號訪問也太蠢了吧的確很蠢,所以我們要慢慢過渡學習。接下來我們學習用來進行反向代理。阿里云的部分有一些配置的具體過程。 一、在linux上部署運行多個tomcat 1、以前的我們 雖然說是在linux上,但是windows上也是同樣的道理,只不過我們服務器都是選用linux罷了。 原先,自己有多個項目需要部署在...

    aikin 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<