Dubbo 日志组件
common.logger 包下.
dubbo 可以配置选用哪种第三方日志框架.
实现
protected static final Logger logger = LoggerFactory.getLogger(AbstractConfig.class);
上面代码做了两件事情
1.第一次会触发 LoggerFactory 类的加载,触发 static 块 里的逻辑;
2.获取logger对象
LoggerFactory 静态代码块逻辑
1.加载 LoggerFactory 和 第三方 Logger
触发 LoggerFactory 加载, 执行静态代码块;
读取系统配置的 logger, 若没配置, 则按照顺序实例化 dubbo logger 的 adapter 类.
adapter 一定能实例化成功,因为构造方法里捕获了异常.
通过 LoggerAdapter 获取 对应的 Logger,此时若依赖的第三方 Logger 不存在,则会失败.
若失败,则再尝试加载其他的第三方 Logger.
static {
String logger = System.getProperty("dubbo.application.logger", ""); // 获取配置的logger
switch (logger) {
case "slf4j":
setLoggerAdapter(new Slf4jLoggerAdapter());
break;
case "jcl":
setLoggerAdapter(new JclLoggerAdapter());
break;
case "log4j":
setLoggerAdapter(new Log4jLoggerAdapter());
break;
case "jdk":
setLoggerAdapter(new JdkLoggerAdapter());
break;
case "log4j2":
setLoggerAdapter(new Log4j2LoggerAdapter());
break;
default: // 没配置的话走这里
List<Class<? extends LoggerAdapter>> candidates = Arrays.asList( // dubbo的各个adapter实现类
Log4jLoggerAdapter.class,
Slf4jLoggerAdapter.class,
Log4j2LoggerAdapter.class,
JclLoggerAdapter.class,
JdkLoggerAdapter.class
);
for (Class<? extends LoggerAdapter> clazz : candidates) {
try {
setLoggerAdapter(clazz.newInstance()); // 1.实例化LoggerAdapter;2.获取第三方Logger,可能会失败,失败尝试下一个
break;
} catch (Throwable ignored) {
}
}
}
}
public static void setLoggerAdapter(LoggerAdapter loggerAdapter) {
if (loggerAdapter != null) {
Logger logger = loggerAdapter.getLogger(LoggerFactory.class.getName()); // 通过 adapter 获取 dubbo logger 对象,里面封装了第三方 logger.若获取失败,调用的地方会尝试加载下一个第三方日志组件.
logger.info("using logger: " + loggerAdapter.getClass().getName());
LoggerFactory.LOGGER_ADAPTER = loggerAdapter; // 给 LOGGER_ADAPTER 赋值
for (Map.Entry<String, FailsafeLogger> entry : LOGGERS.entrySet()) {
entry.getValue().setLogger(LOGGER_ADAPTER.getLogger(entry.getKey()));
}
}
}
获取 Logger 实例
2.获取Logger实例
先从缓存里获取,取到返回;
取不到,则通过 LoggerAdapter 获取 Logger 并缓存.
public static Logger getLogger(Class<?> key) {
return LOGGERS.computeIfAbsent(key.getName(), name -> new FailsafeLogger(LOGGER_ADAPTER.getLogger(name))); // 根据类名获取Logger.若获取不到则创建并缓存
}
- 相当于一个类对应一个Logger对象,如何保证打日志线程安全.
总结
类结构
每种日志框架都提供一个对应的 Logger 类和 LoggerApapter 类. 比如 Log4jLogger, Log4jLoggerAdapter.
Logger 类主要用于对接第三方的api,里面对info(),error()等打印日志的方法进行封装,调用第三方api实现.
Log4jLogger 通过 getLogger() 方法 获取 上面 dubbo 里的 Logger 类对象.
dubbo 日志框架 是什么
为什么需要 dubbo 日志框架
方便对接第三方日志框架,和应用日志保持一致.
dubbo 日志框架 怎么实现
当通过 LoggerFactory.getLogger(xxx.class) 获取日志对象时,做了两件事:
1.第一次会触发 LoggerFactory 类的加载,触发 static 块 里的逻辑;
2.获取logger对象
1.加载 LoggerFactory 和 第三方 Logger
触发 LoggerFactory 加载, 执行静态代码块;
读取系统配置的 logger, 若没配置, 则按照顺序实例化 dubbo logger 的 adapter 类.
adapter 一定能实例化成功,因为构造方法里捕获了异常.
通过 LoggerAdapter 获取 对应的 Logger,此时若依赖的第三方 Logger 不存在,则会失败.
若失败,则再尝试加载其他的第三方 Logger.
2.获取Logger实例
先从缓存里获取,取到返回;
取不到,则通过 LoggerAdapter 获取 Logger 并缓存.