如何做幸运28网站代理,想做一个电影网站该怎么做,网站建设报价新鸿儒,苏州企业服务平台看源码需要先下载源码#xff0c;可以去Mybatis的github上的仓库进行下载#xff0c;Mybatis
这次就先整理一下日志这一块的源码分析#xff0c;这块相对来说比较简单而且这个模块是Mybatis的基础模块。
之前的文章有谈到过Java的日志实现#xff0c;大家也可以参考一下可以去Mybatis的github上的仓库进行下载Mybatis
这次就先整理一下日志这一块的源码分析这块相对来说比较简单而且这个模块是Mybatis的基础模块。
之前的文章有谈到过Java的日志实现大家也可以参考一下日志实现以及使用
我这里看的是目前最新的版本3.5.7版本。
设计模式
我们先来谈谈这个模块用到的设计模式。
在市面上有第三方日志实现但是Mybatis总不可能将每个第三方日志组件实现都做一遍单独的接入所以日志用到的模式叫适配器模式。
适配器模式Adapter Pattern
是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式它结合了两个独立接口的功能。
借用一下网上的UML Target目标角色即期待得到的接口。
Adaptee适配者角色被适配的接口第三方日志接口。
Adapter适配器角色将被适配接口与目标接口进行桥接。
适用场景当调用双方都不太容易修改的时候为了复用现有组件可以使用适配器模式在系统中接入第三方组 件的时候经常被使用到
注意如果系统中存在过多的适配器会增加系统的复杂性设计人员应考虑对系统进行重构
代理模式Proxy Pattern
一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中我们创建具有现有对象的对象以便向外界提供功能接口。
在Mybatis中日志模块用到的代理模式使用将查询的参数结果以及SQL语句进行打印。
源码解析
在源码中org.apache.ibatis.logging包下 Mybatis并没有实现自己的日志接口但是MyBatis统一提供了trace、debug、warn、error四个级别只是定义了一个接口Log一个适配日志工厂LogFactory
在LogFactory的静态代码块中调用的方法顺序为slf4j - commons-logging - log4j2 - log4j - JDKLogging - NoLogging。
所以在没有指定Mybatis的日志类型的时候会去按照这个顺序自动查找对应的第三方日志组件的实现。
package org.apache.ibatis.logging;/*** 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);}package org.apache.ibatis.logging;import java.lang.reflect.Constructor;public final class LogFactory {public static final String MARKER MYBATIS;private static Constructor? extends Log logConstructor;static {tryImplementation(LogFactory::useSlf4jLogging);tryImplementation(LogFactory::useCommonsLogging);tryImplementation(LogFactory::useLog4J2Logging);tryImplementation(LogFactory::useLog4JLogging);tryImplementation(LogFactory::useJdkLogging);tryImplementation(LogFactory::useNoLogging);}private LogFactory() {// disable construction}public static Log getLog(Class? clazz) {return getLog(clazz.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 {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);}}}我们就拿一个示例讲解Log4j
我们找到Log4j的适配器调用的类如下 其他类型的日志组件适配都是以这种形式进行编码的。
第三方的日志组件已经适配好接下来就是将查询过程的各项参数结果集打印。
都知道所有的ORM框架底层都是采用JDBC做查询的Mybatis也不例外。
这里就必须用到了代理模式Mybatis的代理模式是通过JDK的动态代理进行实现的之前讲AOP时讲过这个AOP代理及实现
在Mybatis中查询SQL主要是由Exceutor去查询的默认使用SimpleExecutor 我们进去这个getConnection方法 这个newInstance方法里面是通过JDK动态代理进行创建的 public static Connection newInstance(Connection conn, Log statementLog, int queryStack) {InvocationHandler handler new ConnectionLogger(conn, statementLog, queryStack);ClassLoader cl Connection.class.getClassLoader();return (Connection) Proxy.newProxyInstance(cl, new Class[]{Connection.class}, handler);}所以在拿到Connection链接之后需创建一个Statement对象所以在创建的时候就会进入到invoke方法 这样依次进行代理在使用ResultSet的时候也会进入到对应的代理对象当中 这样日志打印的过程就是这样的
具体的日志类型加载后面会讲日志模块分析就差不多这样讲完了。