loadCustomLogImpl 引入日志工具
解析配置使用的日志系统
XMLConfigBuilder.loadCustomLogImpl(settings);
首先在 mybatis-config.xml
中加入如下配置
<configuration>
<settings>
<setting name="logImpl" value="SLF4J" />
</settings>
</configuration>
这里指定日志工具为 SLF4J
实现,接下来要跟踪下代码具体看看日志工具是如何被指定的。
private void loadCustomLogImpl(Properties props) {
Class<? extends Log> logImpl = resolveClass(props.getProperty("logImpl"));
configuration.setLogImpl(logImpl);
}
通过resolveClass
方法,根据我们传入的参数找到对应的 Class
,其最终实现如下
public <T> Class<T> resolveAlias(String string) {
try {
if (string == null) { eturn null; }
String key = string.toLowerCase(Locale.ENGLISH);
Class<T> value;
if (typeAliases.containsKey(key)) {
value = (Class<T>) typeAliases.get(key);
} else {
value = (Class<T>) Resources.classForName(string);
}
return value;
} catch (ClassNotFoundException e) {}
}
这里如果系统中已经注册了对应的常用类,则使用系统注册的值,否则,使用自自定义的值进行处理。因此,这里填写 SLF4J
和 填写 org.apache.ibatis.logging.slf4j.Slf4jImpl
是等价效果。
查看一下系统中默认已经注册了哪些值。
typeAliasRegistry 是在Configuration
构造方法中进行的初始化
public Configuration() {
......
typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
......
}
可以看到这里注册了 SLF4J
、COMMONS_LOGGING
、LOG4J LOG4J2
、JDK_LOGGING
、STDOUT_LOGGING
、NO_LOGGING
七中方式其中前中是我们常用的日志工具,第六种表示是 System.out.println()
进行标准输出,第七种表示不使用日志。
在找到对应的Class
后 调用 configuration.setLogImpl(logImpl);
方法设置为我们自定义的类,跟踪此方法,找到最后的实现为LogFactory.setImplementation
private static void setImplementation(Class<? extends Log> implClass) {
try {
// 查找字符串参数的构造器
Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
Log log = candidate.newInstance(LogFactory.class.getName());
if (log.isDebugEnabled()) {
log.debug("Logging initialized using '" + implClass + "' adapter.");
}
logConstructor = candidate;
} catch (Throwable t) { }
}
这里最终将系统的日志构造器设置为我们自定义的日志工具的构造器(logConstructor = candidate;
)。
如果没有指定日志系统,即没有配置 <setting name="logImpl" value="SLF4J" />
属性,这个时候日志工厂类就会在系统中寻找默认的额日志工具:
static {
// 这里默认的最高优先级使用的框架是SLF4J,笔者最推荐的也是这种方式。
tryImplementation(LogFactory::useSlf4jLogging);
tryImplementation(LogFactory::useCommonsLogging);
tryImplementation(LogFactory::useLog4J2Logging);
tryImplementation(LogFactory::useLog4JLogging);
tryImplementation(LogFactory::useJdkLogging);
tryImplementation(LogFactory::useNoLogging);
}
......
private static void tryImplementation(Runnable runnable) {
if (logConstructor == null) {
try {
runnable.run();
} catch (Throwable t) { }
}
}
系统会按照优先级依次查找 SLF4J
、COMMONS_LOGGING
、LOG4J
、LOG4J2
、JDK_LOGGING
、NO_LOGGING
是否有对应的日志实现,就是说在使用这几种日志系统的情况下,可以不用显式声明我们使用的日志框架。