设计一个中间件的訪问日志组件

对不论什么一个系统。一个强大的日志记录功能是相当重要且必要的,依据日志的记录能够及时掌握系统执行时的健康状态及故障定位。然而作为web容器存在第二种日志——訪问日志。訪问日志通常会记录client的訪问相关信息,包括clientip、请求时间、请求协议、请求方法、请求字节数、响应码、会话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{

public void log(Request request, Response response){

通过JDBCrequestresponse包括的訪问信息组成一个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的server配置文件配置实现訪问日志记录功能。能够在随意容器中进行配置。


点击订购作者《Tomcat内核设计剖析》



原文地址:https://www.cnblogs.com/yxysuanfa/p/7026256.html