天天看點

設計一個中間件的通路日志元件

對任何一個系統,一個強大的日志記錄功能是相當重要且必要的,根據日志的記錄可以及時掌握系統運作時的健康狀态及故障定位。然而作為web容器存在另外一種日志——通路日志。通路日志一般會記錄用戶端的通路相關資訊,包括用戶端ip、請求時間、請求協定、請求方法、請求位元組數、響應碼、會話id、處理時間等等。通過通路日志可以統計通路使用者的數量、通路時間分布等規律及個人愛好等等,而這些資料可以幫助公司在營運政策上做出抉擇。

如果讓你來設計一個通路日志元件你會如何來設計?你應該很快就會想到通路日志的核心功能就是将資訊記錄下來,至于要記錄到哪裡、以哪種形式來記錄我們先不管,于是很快想到面向接口程式設計定義一個接口AccessLog,方法名就命名為log吧,需要傳遞參數包含請求對象和響應對象,如下,

public interface AccessLog {

 public void log(Request request, Response response);

}

定義一個好的接口是一個良好的開始,接下去要考慮的事是需要哪些類型的元件,針對前面的記錄到哪裡、以哪種形式記錄我們最熟悉也最先想到的肯定就是以檔案形式記錄到磁盤裡,于是我們來實作一個檔案記錄的通路日志元件吧。

public class FileAccessLog implements AccessLog{

public void log(Request request, Response response){

      String message=request與response中的值拼組成你需要的字元串。

try {

    Charset charset = Charset.defaultCharset();

    PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(

                    new FileOutputStream("c:/accesslog.log", true), charset), 128000),

                    false);

    writer.println(message);

    writer.flush();

 } catch (IOException e) {

看起來這是一個簡單且不錯的檔案記錄通路日志元件的實作,起碼用于例子展示讓人一看就覺得簡單明了,采用PrintWriter對象用于寫入操作,而且使用了BufferedWriter添加一個緩沖作用(使用Buffered如何能達到緩沖效果,如果你忘了請看我前面寫的緩沖裝置相關章節,看完一定會對緩沖有一個深入的了解),之是以把緩沖大小設定為128000是經驗得出來的一個适合值,OutputStreamWriter則可以讓字元進行編碼,此處使用Charset工具提供的預設編碼,FileOutputStream則指定寫入的檔案路徑及檔案名,而true表明追加日志而非覆寫。

假如你覺得用sql語言來統計日志的資訊讓你更加得心應手,那就寫到檔案就不符合需求,我們需要另外一個實作,通過jdbc将日志記錄到資料庫中。于是你必須另外建一個JDBCAccessLog類并重新實作log方法,使用JDBC操作資料庫大家是最熟悉不過的了,受篇幅限制不詳細寫實作細節,但有一個前提是你必須跟資料庫約好建立一張特定的表且表的結構要根據通路資訊定義好。

public class JDBCAccessLog implements AccessLog{

通過JDBC把request和response包含的通路資訊組成一個sql語句插入資料庫。

你還可以根據自己的需求定制各種各樣的通路日志元件,隻需實作AccessLog接口。但有時可能你會使用多個通路日志元件,例如又寫入檔案又持久化到資料庫中,這時我們還是提供一個設配器給他吧,

public class AccessLogAdapter implements AccessLog {

    private AccessLog[] logs;

    public AccessLogAdapter(AccessLog log) {

        logs = new AccessLog[] { log };

    }

    public void add(AccessLog log) {

        AccessLog newArray[] = Arrays.copyOf(logs, logs.length + 1);

        newArray[newArray.length - 1] = log;

        logs = newArray;

    public void log(Request request, Response response) {

        for (AccessLog log: logs) {

            log.log(request, response);

        }

經過擴充卡的适配,log方法已經變成了周遊去調用多個通路日志元件的log方法,而擴充卡提供給對外的接口仍然是一個log方法,編寫如下測試類log的調用将會分别向檔案及資料庫記錄下hello tomcat。

public class Test{

public static void main(String[] args){

AccessLog accessLog = new AccessLogAdapter(new FileAccessLog());

accessLog.add(new JDBCAccessLog()); 

accessLog.log(new Request("hello tomcat"),new Response());

經過以上的設計一個良好的通路日志元件就已經成型,而這也是Tomcat的通路日志元件的設計思路,而且Tomcat考慮到子產品化和可配置擴充,它把通路日志元件作為一個管道中的一個閥門(管道機制忘了的朋友請看前面管道機制章節),這樣就可以通過Tomcat的伺服器配置檔案配置實作通路日志記錄功能,可以在任意容器中進行配置。

<a target="_blank" href="https://item.jd.com/12185360.html">點選訂購作者《Tomcat核心設計剖析》</a>