Mybatis-log类详细解析下

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
日志服务 SLS,月写入数据量 50GB 1个月
简介: 《基础系列》

核心类

  • org.apache.ibatis.logging.Log
  • org.apache.ibatis.logging.LogFactory
  • 多个日志实现
  • org.apache.ibatis.logging.log4j2.Log4j2Impl
  • org.apache.ibatis.logging.slf4j.Slf4jLocationAwareLoggerImpl
  • ...

源码流程

  • mybatis 提供了一个日志接口,内容如下.
/**
 * mybatis 的日志接口,提供日志级别
 * <ol>
 *     <li>error</li>
 *     <li>debug</li>
 *     <li>trace</li>
 *     <li>warn</li>
 * </ol>
 * <p>通过自己定义的接口来实现各大日志框架的内容达到高可用</p>
 * @author Clinton Begin
 */
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);
}Copy to clipboardErrorCopied
  • 有了日志接口必然有实现类, mybatis 有log4j2 、 slf4j 等日志的相关实现 , 下面是Slf4jImpl的代码,其他代码也是一样的模式进行初始化就不再重复贴代码了.
public class Slf4jImpl implements Log {
    private Log log;
    /**
     * 创建日志实例
     * @param clazz
     */
    public Slf4jImpl(String clazz) {
        Logger logger = LoggerFactory.getLogger(clazz);
        if (logger instanceof LocationAwareLogger) {
            try {
                // check for slf4j >= 1.6 method signature
                logger.getClass().getMethod("log", Marker.class, String.class, int.class, String.class, Object[].class, Throwable.class);
                log = new Slf4jLocationAwareLoggerImpl((LocationAwareLogger) logger);
                return;
            } catch (SecurityException | NoSuchMethodException e) {
                // fail-back to Slf4jLoggerImpl
            }
        }
        // Logger is not LocationAwareLogger or slf4j version < 1.6
        log = new Slf4jLoggerImpl(logger);
    }
    @Override
    public boolean isDebugEnabled() {
        return log.isDebugEnabled();
    }
    @Override
    public boolean isTraceEnabled() {
        return log.isTraceEnabled();
    }
    @Override
    public void error(String s, Throwable e) {
        log.error(s, e);
    }
    @Override
    public void error(String s) {
        log.error(s);
    }
    @Override
    public void debug(String s) {
        log.debug(s);
    }
    @Override
    public void trace(String s) {
        log.trace(s);
    }
    @Override
    public void warn(String s) {
        log.warn(s);
    }
}
Copy to clipboardErrorCopied
  • 通过上述方法来达到统一接口多个实现,这个在开发中也经常使用.多日志的实现方法有了还缺一个创建方法,创建方法由org.apache.ibatis.logging.LogFactory提供
/**
 * <p>日志工厂,实现内容:</p>
 * <ol>
 *     <li>org.slf4j.Logger 日志框架 slf4j</li>
 *     <li>org.apache.commons.logging.Log 日志框架 apache</li>
 *     <li>org.apache.logging.log4j.Logger 日志框架 log4j2</li>
 *     <li>org.apache.log4j.Logger 日志框架 log4j </li>
 *     <li>java.util.logging.Logger 日志框架,JDK的logger</li>
 *
 * </ol>
 * @author Clinton Begin
 * @author Eduardo Macarron
 */
public final class LogFactory {
    /**
     * Marker to be used by logging implementations that support markers.
     */
    public static final String MARKER = "MYBATIS";
    private static Constructor<? extends Log> logConstructor;
    /**
     * 日志的实现类的具体选择
     */
    static {
        // slf4j 日志
        tryImplementation(LogFactory::useSlf4jLogging);
        // apache 日志
        tryImplementation(LogFactory::useCommonsLogging);
        // log4j2 日志
        tryImplementation(LogFactory::useLog4J2Logging);
        // log4 日志
        tryImplementation(LogFactory::useLog4JLogging);
        // JDK 日志
        tryImplementation(LogFactory::useJdkLogging);
        // 空 日志
        tryImplementation(LogFactory::useNoLogging);
    }
    /**
     * 私有化构造方法,这是一个单例
     */
    private LogFactory() {
        // disable construction
    }
    public static Log getLog(Class<?> aClass) {
        return getLog(aClass.getName());
    }
    public static Log getLog(String logger) {
        try {
            return logConstructor.newInstance(logger);
        } catch (Throwable t) {
            throw new LogException("Error creating logger for logger " + logger + ".  Cause: " + t, t);
        }
    }
    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 {
                // run()? 似乎违背了代码的语义, 看静态方法.静态方法多行同类型的操作我认为是一个多线程
                runnable.run();
            } catch (Throwable t) {
                // ignore
            }
        }
    }
    /**
     * 选择具体的日志实现
     */
    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) {
            throw new LogException("Error setting Log implementation.  Cause: " + t, t);
        }
    }
}
Copy to clipboardErrorCopied
  • LogFactory是一个单例对象,对外公开getLog方法在使用时直接private static final Log log = LogFactory.getLog(CglibProxyFactory.class);即可
  • 在 org.apache.ibatis.session.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);
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
21天前
|
存储 Java API
详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
【10月更文挑战第19天】深入剖析Java Map:不仅是高效存储键值对的数据结构,更是展现设计艺术的典范。本文从基本概念、设计艺术和使用技巧三个方面,详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
37 3
|
21天前
|
存储 监控 安全
深入解析Sysmon日志:增强网络安全与威胁应对的关键一环
在不断演进的网络安全领域中,保持对威胁的及时了解至关重要。Sysmon日志在这方面发挥了至关重要的作用,通过提供有价值的见解,使组织能够加强其安全姿态。Windows在企业环境中是主导的操作系统,因此深入了解Windows事件日志、它们的独特特性和局限性,并通过Sysmon进行增强,变得至关重要。
|
1月前
|
存储 编译器 数据安全/隐私保护
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解2
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
29 3
|
1月前
|
编译器 C++
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解1
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
44 3
|
23天前
|
存储 关系型数据库 MySQL
MySQL中的Redo Log、Undo Log和Binlog:深入解析
【10月更文挑战第21天】在数据库管理系统中,日志是保障数据一致性和完整性的关键机制。MySQL作为一种广泛使用的关系型数据库管理系统,提供了多种日志类型来满足不同的需求。本文将详细介绍MySQL中的Redo Log、Undo Log和Binlog,从背景、业务场景、功能、底层实现原理、使用措施等方面进行详细分析,并通过Java代码示例展示如何与这些日志进行交互。
39 0
|
2月前
|
存储 缓存 关系型数据库
redo log 原理解析
redo log 原理解析
40 0
redo log 原理解析
|
2月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP的编程实践中,设计模式是解决常见软件设计问题的最佳实践。单例模式作为设计模式中的一种,确保一个类只有一个实例,并提供全局访问点,广泛应用于配置管理、日志记录和测试框架等场景。本文将深入探讨单例模式的原理、实现方式及其在PHP中的应用,帮助开发者更好地理解和运用这一设计模式。
在PHP开发中,单例模式通过确保类仅有一个实例并提供一个全局访问点,有效管理和访问共享资源。本文详细介绍了单例模式的概念、PHP实现方式及应用场景,并通过具体代码示例展示如何在PHP中实现单例模式以及如何在实际项目中正确使用它来优化代码结构和性能。
44 2
|
1月前
|
程序员 开发者 Python
深度解析Python中的元编程:从装饰器到自定义类创建工具
【10月更文挑战第5天】在现代软件开发中,元编程是一种高级技术,它允许程序员编写能够生成或修改其他程序的代码。这使得开发者可以更灵活地控制和扩展他们的应用逻辑。Python作为一种动态类型语言,提供了丰富的元编程特性,如装饰器、元类以及动态函数和类的创建等。本文将深入探讨这些特性,并通过具体的代码示例来展示如何有效地利用它们。
35 0
|
2月前
|
存储 运维 监控
超级好用的C++实用库之日志类
超级好用的C++实用库之日志类
38 0
|
3月前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
44 0
Spring高手之路22——AOP切面类的封装与解析

推荐镜像

更多