在第一小節中經過幾步一個通路日志元件已成型,但為了增加使用者自定義能力我們還是要繼續做點事,對于使用者自定義的實作最經典的做法就是引入變量表示,例如定義%a表示遠端主機IP、%A表示本機IP等等,然後在寫入之前用相應邏輯把變量替換成相應的值寫入日志。這節我們來實作日志格式的自定義支援。
整個過程其實是先自定義變量組,再逐個把變量替換成相應值,最後把替換後的值寫入檔案。由于需要實作很多不同的變量,是以定義一個接口用于限制所有變量添加操作的定義,定義一個addElement方法,通過從request和response擷取相應的變量值後添加到字元串buf中。
public interface AccessLogElement {
public void addElement(StringBuilder buf, Request request, Response response);
}
接着定義兩個元素分别用于添加響應狀态碼和遠端位址,使用時直接調用他們的addElement即可把狀态碼和遠端位址添加到字元串中,
public class StatusCodelElement implements AccessLogElement {
public void addElement(StringBuilder buf, Request request, Response response) {
buf.append(response.getStatus());
public class RemoteAddrElement implements AccessLogElement {
buf.append(request.getRemoteAddr());
現在還差一個映射器用于解析變量到各自AccessLogElement的映射,如下ElementMapping提供一個map方法把自定義的pattern解析成對應的通路日志元素并發對應的值替換原來的變量。
public class ElementMapping {
Response response;
Request reqeust;
public ElementMapping(Request request, Response response){
this.reqeust=request;
this.response=response;
public StringBuilder map(String pattern) {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < pattern.length(); i++) {
char ch = pattern.charAt(i);
if (ch == '%') {
ch = pattern.charAt(++i);
addElement(ch, buf);
} else {
buf.append(ch);
return buf;
private void addElement(char ch, StringBuilder buf) {
switch (ch) {
case 'a':
new RemoteAddrElement().addElement(buf, request, response);
break;
case 's':
new StatusCodeElement().addElement(buf, request, response);
這節介紹的是如何引入變量使你的通路日志元件擁有自定義格式功能,并且使用了一個簡單的案例說明,如果你想擁有更強大的自定義能力可以在本文基礎上實作,例如可以把常用的變量組合簡化為一個字元串表示,common字元串用于表示%h %l %u %t "%r" %s %b常用的變量組合,當然要實作這樣的支援你必須在映射器中做對應的處理。
<a target="_blank" href="https://item.jd.com/12185360.html">點選訂購作者《Tomcat核心設計剖析》</a>