亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Tomcat的Logging內部實現方式是什么

發布時間:2021-12-08 18:24:17 來源:億速云 閱讀:124 作者:柒染 欄目:大數據

今天就跟大家聊聊有關Tomcat的Logging內部實現方式是什么,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

Tomcat的Logging實現,是通過JDK的Log,并重寫了其Log的Handler來輸出內容的。

下面將分析在Tomcat內部Log的實現,并深入源碼,了解其根據配置,創建

Handler等一系列過程。

初始化

Tomcat的Main-Class是BootStrap這個類,而Log的初始化也是從這個類的初始化開始的,由于BootStrap類中有如下聲明:

private static final Log log = LogFactory.getLog(Bootstrap.class)

所以在類實例化時,這一字段也被初始化。

從LogFactory的工廠方法開始

public Log getInstance(String name) {
   if (discoveredLogConstructor == null) {
       return DirectJDKLog.getInstance(name);
   }
  return discoveredLogConstructor.newInstance(name);

默認情況,Tomcat使用的是DirectJDKLog,因此,后續的過程都交給了

DirectJDKLog來處理。該類內部則是直接對JDK的logging調用

public DirectJDKLog(String name ) {
   logger=Logger.getLogger(name);
}

而整個Logger其實還是會交給一個LogManager來管理,上一篇文章中我們也看到Tomcat也指定了自定義的LogManager,

這個類是ClassLoaderLogManager

在Logger獲取LogManager的過程中,就會涉及到讀取logging.properties的過程,此時由于ClassLoaderLogManager繼承了LogManager,這個readConfiguration方法由子類實現了,此時Tomcat的自定義讀取方式如下:

URL logConfig = ((URLClassLoader)classLoader).findResource("logging.properties");

即在當前的classLoader中查找名為logging.properties的資源。如果當前classLoader中不存在會使用JDK自帶的logging.properties,找到文件之后,會直接把這個properties文件load進來,之后對文件中的properties解析。

如同下面的代碼,我們看到解析handlers,同時會解析自定義的帶有prefix的handler。

// Create handlers for the root logger of this classloader
String rootHandlers = info.props.getProperty(".handlers");
String handlers = info.props.getProperty("handlers");
Logger localRootLogger = info.rootNode.logger;
if (handlers != null) {
   StringTokenizer tok = new StringTokenizer(handlers, ",");
   while (tok.hasMoreTokens()) {
       String handlerName = (tok.nextToken().trim());
       String handlerClassName = handlerName;
       String prefix = "";
       if (handlerClassName.length() <= 0) {
           continue;
       }
     if (Character.isDigit(handlerClassName.charAt(0))) {
           int pos = handlerClassName.indexOf('.');
           if (pos >= 0) {
               prefix = handlerClassName.substring(0, pos + 1);
               handlerClassName = handlerClassName.substring(pos + 1);}}
       try {
           this.prefix.set(prefix);
           Handler handler =
               (Handler) classLoader.loadClass(handlerClassName).newInstance(); //解析prefix和handlerClass后設置,在newInstance后,其實執行了許多操作,包含設置和初始化具體的Handler,打開輸出流等。上篇文章提到的設置Log文件的操作就在這一步。
           this.prefix.set(null);
           info.handlers.put(handlerName, handler);
           if (rootHandlers == null) {
               localRootLogger.addHandler(handler);} //解析完畢后,將handler和logger綁定。
       } catch (Exception e) {}

而在loadClass(handlerClassName).newInstance中,還有比較關鍵的一個地方,在初始化AsynFileHandler時,類內初始化的代碼包含這樣兩行

protected static final LoggerThread logger = new LoggerThread();
static {
   logger.start();
}

這個Logger線程,則會在后面不停止的處理log,其run方法是這個樣子:

while (run) {
   try {
       LogEntry entry = queue.poll(LOGGER_SLEEP_TIME, TimeUnit.MILLISECONDS);//log出隊列
       if (entry!=null) entry.flush();
   } catch (InterruptedException x) {
       // Ignore the attempt to interrupt the thread.
   } catch (Exception x) {
       x.printStackTrace();
   }
}
 


記一個Log

而我們一般在記錄log時,會直接使用log.info(xxx)這種形式,Tomcat內部也是這樣的。

例如要用log記一個log.warn,這個時候,調用執行的代碼是這樣一個過程:

首先會調用到上面提到的DirectJDKLog中,其對應的方法會設置Log的Level等,方法是這個樣子:

public final void warn(Object message) {
   log(Level.WARNING, String.valueOf(message), null);
}

這行代碼,會調用到Logger中的如下代碼,會根據配置的Handler來進行log輸出

for (Handler handler : loggerHandlers) {
   handler.publish(record);
}

我們定義的Handler中包含FileHandler和ConsoleHandler,這個時候,FileHandler的publish方法執行的操作是將Log添加到一個阻塞隊列中,即上面的LogThread在wait的隊列,

public void publish(LogRecord record) {
  LogEntry entry = new LogEntry(record,this);
   boolean added = false;
   try {
       while (!added && !queue.offer(entry)) {...}

logThread在queue不為空時,會輸出LogEntry。

我們看,這個輸出Log的具體操作方式如下,會使用到上一篇文章提到的Formatter,

public void publish(LogRecord record) {
   Timestamp ts = new Timestamp(System.currentTimeMillis());
   String tsString = ts.toString().substring(0, 19);
   String tsDate = tsString.substring(0, 10);

   try {
       // If the date has changed, switch log files
       if (rotatable && !date.equals(tsDate)) {
           try {
               // Make sure another thread hasn't already done this
               if (!date.equals(tsDate)) {
                   closeWriter();
                   date = tsDate;
                   openWriter();
               }}}

       String result = null;
       result = getFormatter().format(record); //格式化,注意
         if (writer!=null) {
               writer.write(result); //這里使用初始化時創建的Writer
               if (bufferSize < 0) {
                   writer.flush();
               }

看完上述內容,你們對Tomcat的Logging內部實現方式是什么有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

枝江市| 潞城市| 浑源县| 福贡县| 东乌珠穆沁旗| 荥阳市| 开平市| 万年县| 安龙县| 保康县| 深州市| 教育| 白朗县| 连平县| 昌乐县| 竹溪县| 朝阳区| 杨浦区| 疏附县| 茌平县| 延安市| 大余县| 色达县| 临城县| 湖州市| 三明市| 石门县| 天气| 万荣县| 双辽市| 芜湖市| 清远市| 门头沟区| 长春市| 呼伦贝尔市| 宜丰县| 苏州市| 河东区| 剑河县| 惠州市| 盘山县|