• Mybatis框架基础支持层——日志模块(8)


    前言

    java开发中常用的日志框架有Log4j,Log4j2,Apache Commons Log,java.util.logging,slf4j等,这些工具对外的接口不尽相同。为了统一这些工具的接口,Mybatis定义了一套统一的日志接口供上层调用,并为上述日志框架提供了相应的适配器。

    在Mybatis的日志模块中,使用了适配器模式。Mybatis调用其他日志模块时,使用了其内部接口(org.apache.ibatis.logging.Log接口)。但是第三方日志组件对外提供的接口各不相同,Mybatis为了集成和服用这些第三方日志组件,在其模块中提供了多种Adapter,将这些第三方日志组件对外接口适配成了org.apache.ibatis.logging.Log接口,这样Mybatis内部就可以统一通过org.apache.ibatis.logging.Log接口调用第三方日志组件的功能了。

    日志适配器

    Mybatis的日志模块位于org.apache.ibatis.logging包中,改模块中的Log接口定义了日志模块的功能,当然日志适配器也会实现此接口。LogFactory工厂类负责创建对应的日志组件适配器。

    LogFactory类解析:

    /**
     * 在LogFactory类加载时会执行其静态代码块,其逻辑是按序加载并实例化对应的日志适配器,
     * 然后使用LogConstructor这个静态字段,记录当前使用的第三方日志组件适配器
     */
    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;
    
        /**
         * 对每种日志组件调用tryImplementation()进行尝试加载,具体的调用顺序是:
         * useSlf4jLogging——>useCommonsLogging——>useLog4J2Logging
         * ——>useLog4JLogging——>useJdkLogging——>useNoLogging
         */
        static {
            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();
                }
            });
        }
    
        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);
        }
        /**
         * 使用Slf4j日志组件
         */
        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);
        }
    
        /**
         * 此方法会先检测logConstructor,若为空则调用runnable.run()方法
         */
        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 {
                //获取指定适配器的构造方法
                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字段
                logConstructor = candidate;
            } catch (Throwable t) {
                throw new LogException("Error setting Log implementation.  Cause: " + t, t);
            }
        }
    
    }

    JDBC调试

    在Mybatis的日志模块中有一个jdbc包,它并不是将日志信息通过jdbc存入数据库,而是通过JDK动态代理的方式,将JDBC操作通过制定的日志框架打印出来。这个功能通常在开发阶段使用,它可以输出sql语句、用户传入的参数、sql影响的行数等信息。对调试程序非常有用。

    BaseJdbcLogger是一个抽象类,它是jdbc包下其他Logger类的父类,具体作用请看源码分析,此处不贴源码:

  • 相关阅读:
    Java并发
    JS的强制类型转换
    JS的原生函数
    JS的类型和值
    解决Oracle临时表空间占满的问题
    nginx location匹配规则
    java.util.ConcurrentModificationException 解决办法
    SQL优化三板斧:精简之道、驱动为王、集合为本
    一次非典型SQL优化:如何通过业务逻辑优化另辟蹊径?
    一次耐人寻味的SQL优化:除了SQL改写,还要考虑什么?
  • 原文地址:https://www.cnblogs.com/wly1-6/p/10341316.html
Copyright © 2020-2023  润新知