Dubbo日誌打印剖析(自適配)

Dubbo 的日誌打印機制

在以往的業務系統項目中,常常引入咱們想接入的日誌輸出POM依賴, 利用相應的Logger API 輸出日誌或想打印的信息。但在依賴Spring Framework,Dubbo 或者其餘項目時發現,只須要引入Logger相關Jar包依賴,就能夠自適配Log 輸出,利用適配後的日誌輸出系統打印相關信息。 它們的自適配是如何實現的呢?java

這些框架是如何實現不一樣的日誌系統與日誌API解耦的

  • Dubbo本身實現了本身的日誌打印系統
  • Spring Framework使用了 apache 的 commons-logging 來實現不一樣方式的日誌打印與獲取日誌對象的解耦

首先分析下Dubbo源碼的日誌實現

Dubbo日誌的調用方式,針對不一樣的日誌打印系統,採用統一的API調用及輸出,如:apache

/**
 * ChannelListenerDispatcher
 *
 * @author william.liangf
 */
public class ChannelHandlerDispatcher implements ChannelHandler {

    private static final Logger logger = LoggerFactory.getLogger(ChannelHandlerDispatcher.class);
    ........
}

LoggerFactory.getLogger 就能夠獲取這個類的統一的調用對象。設計模式

接下來查看日誌相關源碼位置app

Dubbo日誌結構圖

Dubbo 日誌相關代碼在common.logger下,分模塊分包也是Dubbo模塊化分層的方式之一。框架

日誌系統UML圖以下所示:模塊化

Dubbo日誌結構圖

用到的設計模式:

裝飾者模式

Dubbo中的適配器模式

適配器模式

Dubbo中的裝飾者模式

核心源碼

Dubbo採用的日誌輸出方式是首先從dubbo.application.logger 系統變量中獲取屬性值,來判斷到底採用哪一種日誌輸出方式,若是沒設置則按照默認的加載順序加載相應的日誌輸出類,直到成功加載:spa

順序爲:log4jLogger > slf4jLogger > JclLogger > JdkLogger 。設計

接下來看LoggerFactory在類加載過程當中變量的初始化過程:日誌

static {
    String logger = System.getProperty("dubbo.application.logger");
    if ("slf4j".equals(logger)) {
        setLoggerAdapter(new Slf4jLoggerAdapter());
    } else if ("jcl".equals(logger)) {
        setLoggerAdapter(new JclLoggerAdapter());
    } else if ("log4j".equals(logger)) {
        setLoggerAdapter(new Log4jLoggerAdapter());
    } else if ("jdk".equals(logger)) {
        setLoggerAdapter(new JdkLoggerAdapter());
    } else {
        try {
            setLoggerAdapter(new Log4jLoggerAdapter());
        } catch (Throwable e1) {
            try {
                setLoggerAdapter(new Slf4jLoggerAdapter());
            } catch (Throwable e2) {
                try {
                    setLoggerAdapter(new JclLoggerAdapter());
                } catch (Throwable e3) {
                    setLoggerAdapter(new JdkLoggerAdapter());
                }
            }
        }
    }
}

能夠看出相關加載過程。code

LoggerFactory中有兩個靜態變量

private static final ConcurrentMap<String, FailsafeLogger> LOGGERS = new ConcurrentHashMap<String, FailsafeLogger>();
private static volatile LoggerAdapter LOGGER_ADAPTER;

LOGGER_ADAPTER 保存輸出方式對應的適配器對象。(切換日誌輸出時,保證內存的可見)

LOGGERS 存有不一樣Service業務類對象的Logger對象。 避免同一業務類的Logger對象頻繁建立問題。 (避免了業務人員對每次業務方法都經過LoggerFactory.getLogger 獲取Logger對象,致使的Logger對象的頻繁建立問題)

Dubbo經過這種方式在系統初始化(類加載)期間,完成了Logger的選型工做。

注: Logger 的選中根 dubbo.application.logger 系統變量設定 和 類加載順序相關

讚揚支持

讚揚支持

相關文章
相關標籤/搜索