java 日志模块_[Mybatis源码分析-1]日志模块

日志模块概述

Mybatis没有自己的日志实现,支持部分开源日志实现和用户自定义日志实现。支持的第三方框架有:Slf4J、CommonsLogging、Log4J、Log4J2、JdkLogging,还支持StdOutLogging(输出到控制台)、NoLogging(不输出日志)。如果使用自定义的日志实现,那么需要实现Mybatis定义的Log接口。

Mybatis按照Slf4J -> CommonsLogging -> Log4J2 -> Log4J -> JdkLogging -> NoLogging的顺序,加载第三方日志框架。Mybatis定义了一个日志工厂类LogFactory,在类加载的时候,就按顺序尝试到底使用哪个第三方日志框架。

package org.apache.ibatis.logging;

import java.lang.reflect.Constructor;

/**

* @author Clinton Begin

* @author Eduardo Macarron

*/

//mybatis自己实现的日志工厂

public final class LogFactory {

/**

* Marker to be used by logging implementations that support markers

*/

public static final String MARKER = "MYBATIS";

//Log是Mybatis自己定义的日志顶级接口

//Mybatis定义了一些开源日志框架的包装类,实现了Log接口

//logConstructor是使用的开源日志框架的包装类的构造函数

private static Constructor extends Log> logConstructor;

static {

//类加载的时候,就要确定好到底使用哪个开源日志框架。mybatis按顺序尝试。

//这里并不是多线程,因为tryImplementation方法里调用的是run(),而不是start(),所以没有开启多线程

tryImplementation(new Runnable() {

@Override

public void run() {

useSlf4jLogging();

}

});

tryImplementation(new Runnable() {

@Override

public void run() {

useCommonsLogging();

}

});

tryImplementation(new Runnable() {

@Override

public void run() {

useLog4J2Logging();

}

});

tryImplementation(new Runnable() {

@Override

public void run() {

useLog4JLogging();

}

});

tryImplementation(new Runnable() {

@Override

public void run() {

useJdkLogging();

}

});

tryImplementation(new Runnable() {

@Override

public void run() {

useNoLogging();

}

});

}

//LogFactory不允许实例化

private LogFactory() {

// disable construction

}

public static Log getLog(Class> aClass) {

return getLog(aClass.getName());

}

public static Log getLog(String logger) {

try {

//所有的日志包装类,都必须有一个带唯一String参数的构造方法,这样才能new一个日志包装类实例

return logConstructor.newInstance(logger);

} catch (Throwable t) {

throw new LogException("Error creating logger for logger " + logger + ". Cause: " + t, t);

}

}

//提供了扩展,如果不用Mybatis支持的日志框架,可以用自定义的日志实现

//只要自定义的日志实现,也实现了Log接口,并要有一个带String参数的构造方法,否则会实例化失败。

public static synchronized void useCustomLogging(Class extends Log> clazz) {

setImplementation(clazz);

}

public static synchronized void useSlf4jLogging() {

setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class);

}

public static synchronized void useCommonsLogging() {

setImplementation(org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.class);

}

public static synchronized void useLog4JLogging() {

setImplementation(org.apache.ibatis.logging.log4j.Log4jImpl.class);

}

public static synchronized void useLog4J2Logging() {

setImplementation(org.apache.ibatis.logging.log4j2.Log4j2Impl.class);

}

public static synchronized void useJdkLogging() {

setImplementation(org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl.class);

}

public static synchronized void useStdOutLogging() {

setImplementation(org.apache.ibatis.logging.stdout.StdOutImpl.class);

}

public static synchronized void useNoLogging() {

setImplementation(org.apache.ibatis.logging.nologging.NoLoggingImpl.class);

}

/**尝试加载日志实现类,如果已经加载过了,就不加载第二个*/

private static void tryImplementation(Runnable runnable) {

if (logConstructor == null) {

try {

runnable.run();

} catch (Throwable t) {

// ignore

}

}

}

private static void setImplementation(Class extends Log> implClass) {

try {

//先拿到Log接口的实现类的构造器对象(也就是Mybatis日志包装类的构造器对象,并且构造函数的参数是唯一String)

Constructor extends Log> candidate = implClass.getConstructor(String.class);

//拿到构造器对象后,通过反射,new一个包装类对象。

//传入参数为LogFactory的全类名,实际上这个全类名是传给具体的日志框架的。

Log log = candidate.newInstance(LogFactory.class.getName());

if (log.isDebugEnabled()) {

//如果是debug级别,就告诉程序员,日志框架的包装类实例化完毕。间接告诉我们,这里用到了设计模式:适配器模式。

log.debug("Logging initialized using '" + implClass + "' adapter.");

}

//如果到这一步,没抛出异常,说明找到了相应的日志框架的jar包了,也就不会再找其他的了。

logConstructor = candidate;

} catch (Throwable t) {

//抛出错误,说明没找到jar包。但是这个错误信息会被上层忽略。

throw new LogException("Error setting Log implementation. Cause: " + t, t);

}

}

}

因为各个开源框架支持的日志级别不同,Mybatis选择支持error、debug、trace、warn4种级别。

package org.apache.ibatis.logging;

/**

* @author Clinton Begin

*/

//Mybatis定义了自己的Log接口,而不是直接使用日志的实现框架。

public interface Log {

boolean isDebugEnabled();

boolean isTraceEnabled();

void error(String s, Throwable e);

void error(String s);

void debug(String s);

void trace(String s);

void warn(String s);

}

Mybatis如何兼容不同日志框架

log4j(与NoLogging、StdOutLogging、JdkLogging、Log4J2、CommonsLogging、Slf4J本质是一样的)

兼容log4j十分简单,Mybatis定义了一个Log4jImpl类,实现了顶层接口org.apache.ibatis.logging.Log,Log4jImpl只有一个带String类型参数的构造器,并组合了Log4j实例,对Log4jImpl的方法调用,实际上是对Log4j实例的方法调用。这里用到适配器模式。

package org.apache.ibatis.logging.log4j;

import org.apache.ibatis.logging.Log;

import org.apache.log4j.Level;

import org.apache.log4j.Logger;

/**

* @author Eduardo Macarron

*/

public class Log4jImpl implements Log {

private static final String FQCN = Log4jImpl.class.getName();

private final Logger log;

public Log4jImpl(String clazz) {

log = Logger.getLogger(clazz);

}

@Override

public boolean isDebugEnabled() {

return log.isDebugEnabled();

}

@Override

public boolean isTraceEnabled() {

return log.isTraceEnabled();

}

@Override

public void error(String s, Throwable e) {

log.log(FQCN, Level.ERROR, s, e);

}

@Override

public void error(String s) {

log.log(FQCN, Level.ERROR, s, null);

}

@Override

public void debug(String s) {

log.log(FQCN, Level.DEBUG, s, null);

}

@Override

public void trace(String s) {

log.log(FQCN, Level.TRACE, s, null);

}

@Override

public void warn(String s) {

log.log(FQCN, Level.WARN, s, null);

}

}

jdbc日志

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值