mybatis源码解析五之设计模式

单例模式

利用static的特性,类加载器只会加载一次同时上锁的特性,实现懒加载.

public abstract class VFS {

  private static class VFSHolder {
    static final VFS INSTANCE = createVFS();

    @SuppressWarnings("unchecked")
    static VFS createVFS() {
      // Try the user implementations first, then the built-ins
      // 优先使用用户自定义的VFS 实现, 如没有自定义VFS 实现,则使用MyBatis 提供的VFS 实现
      List<Class<? extends VFS>> impls = new ArrayList<>();
      impls.addAll(USER_IMPLEMENTATIONS);
      impls.addAll(Arrays.asList((Class<? extends VFS>[]) IMPLEMENTATIONS));

      // Try each implementation class until a valid one is found
     //遍历集合,依次实例化VFS 对象并检测VFS 对象是否有效,一旦得到有效的VFS 对象,则结束循环
      VFS vfs = null;
      for (int i = 0; vfs == null || !vfs.isValid(); i++) {
        Class<? extends VFS> impl = impls.get(i);
        try {
          vfs = impl.getDeclaredConstructor().newInstance();
          if (!vfs.isValid() && log.isDebugEnabled()) {
            log.debug("VFS implementation " + impl.getName()
                + " is not valid in this environment.");
          }
        } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
          log.error("Failed to instantiate " + impl, e);
          return null;
        }
      }

      if (log.isDebugEnabled()) {
        log.debug("Using VFS adapter " + vfs.getClass().getName());
      }

      return vfs;
    }
  }

  /**
   * Get the singleton {@link VFS} instance. If no {@link VFS} implementation can be found for the current environment,
   * then this method returns null.
   *
   * @return single instance of VFS
   */
  public static VFS getInstance() {
    return VFSHolder.INSTANCE;
  }
}

适配器模式

针对不同的log组件统一只进行4种日志处理,trace 、debug 、
warn 、error 四个级别

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 {
    //下面会针对每种日志组件调用tr yimplementation ( )方法进行尝试加载,具体调用顺序是:
    //useSlf4jLogging ()一> useCommonsLogging ()一> useLog4J2Logging ()一〉
    // useLog 4JLogging()--> useJdkLogging() -> useNoLogging()
    tryImplementation(LogFactory::useSlf4jLogging);
    tryImplementation(LogFactory::useCommonsLogging);
    tryImplementation(LogFactory::useLog4J2Logging);
    tryImplementation(LogFactory::useLog4JLogging);
    tryImplementation(LogFactory::useJdkLogging);
    tryImplementation(LogFactory::useNoLogging);
  }
  }

在这里插入图片描述

代理模式

public final class ConnectionLogger extends BaseJdbcLogger implements InvocationHandler {

 @Override
  public Object invoke(Object proxy, Method method, Object[] params)
      throws Throwable {
    try {
      //如调用的是从Object继承的方法,则直接调用,不做任何其他处理
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, params);
      }
      //如果调用的是prepareStatement ()方法、prepareCall ()方法或createStatement()方法,
//则在创建相应Statement 对象后,为其创建代理对象并返回该代理对象
      if ("prepareStatement".equals(method.getName()) || "prepareCall".equals(method.getName())) {
        // 日志输出
        if (isDebugEnabled()) {
          debug(" Preparing: " + removeBreakingWhitespace((String) params[0]), true);
        }
        PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params);
      //为该PreparedStatement 对象创建代理对象
        stmt = PreparedStatementLogger.newInstance(stmt, statementLog, queryStack);
        return stmt;
      } else if ("createStatement".equals(method.getName())) {
        Statement stmt = (Statement) method.invoke(connection, params);
        stmt = StatementLogger.newInstance(stmt, statementLog, queryStack);
        return stmt;
      } else {
        return method.invoke(connection, params);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }

  /**
   * Creates a logging version of a connection.
   *
   * @param conn
   *          the original connection
   * @param statementLog
   *          the statement log
   * @param queryStack
   *          the query stack
   * @return the connection with logging
   */
  public static Connection newInstance(Connection conn, Log statementLog, int queryStack) {
    //使用JDK 动态代理的方式创建代理对象
    InvocationHandler handler = new ConnectionLogger(conn, statementLog, queryStack);
    ClassLoader cl = Connection.class.getClassLoader();
    return (Connection) Proxy.newProxyInstance(cl, new Class[]{Connection.class}, handler);
  }


}

责任链模式

org.apache.ibatis.logging.jdbc.ConnectionLogger#invoke方法,针对不同的操作处理,交给不同的Logger处理

在这里插入图片描述

public final class PreparedStatementLogger extends BaseJdbcLogger implements InvocationHandler {
 @Override
  public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, params);
      }
      //调用了EXECUTE_METHODS集合中的方法
      if (EXECUTE_METHODS.contains(method.getName())) {
        if (isDebugEnabled()) {
          // 日志输出,输出的是参数值以及参数类型
          debug("Parameters: " + getParameterValueString(), true);
        }
        // 清空BaseJdbcLogger 中定义的三个column *集合
        clearColumnInfo();

        if ("executeQuery".equals(method.getName())) {
          //如果调用executeQuery ()方法, 则为ResultSet 创建代理对象
          ResultSet rs = (ResultSet) method.invoke(statement, params);
          return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack);
        } else {
          return method.invoke(statement, params);
        }
      } else if (SET_METHODS.contains(method.getName())) {
        //如果调用SET_METHODS 集合中的方法, 则通过setColumn ()方法记录到BaseJdbcLogger 中定义的三个column *集合
        if ("setNull".equals(method.getName())) {
          setColumn(params[0], null);
        } else {
          setColumn(params[0], params[1]);
        }
        return method.invoke(statement, params);
      } else if ("getResultSet".equals(method.getName())) {
        //如果调用getResultSet ()方法,则为ResultSet创建代理对象
        ResultSet rs = (ResultSet) method.invoke(statement, params);
        return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack);
      } else if ("getUpdateCount".equals(method.getName())) {
        //如果调用getUpdateCount ( )方法,则通过日志框架输出其结果
        int updateCount = (Integer) method.invoke(statement, params);
        if (updateCount != -1) {
          debug("   Updates: " + updateCount, false);
        }
        return updateCount;
      } else {
        return method.invoke(statement, params);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }

  /**
   * Creates a logging version of a PreparedStatement.
   *
   * @param stmt - the statement
   * @param statementLog - the statement log
   * @param queryStack - the query stack
   * @return - the proxy
   */
  public static PreparedStatement newInstance(PreparedStatement stmt, Log statementLog, int queryStack) {
    InvocationHandler handler = new PreparedStatementLogger(stmt, statementLog, queryStack);
    ClassLoader cl = PreparedStatement.class.getClassLoader();
    return (PreparedStatement) Proxy.newProxyInstance(cl, new Class[]{PreparedStatement.class, CallableStatement.class}, handler);
  }

}

在这里插入图片描述

工厂模式

每个数据源工厂构造不同的数据源

public interface DataSourceFactory {
//设置Data Source 的相关属性,一般紧跟在初始化完成之后
  void setProperties(Properties props);
//获取DataSource 对象
  DataSource getDataSource();

}
public class UnpooledDataSourceFactory implements DataSourceFactory {
  public UnpooledDataSourceFactory() {
    this.dataSource = new UnpooledDataSource();
  }
}
public class PooledDataSourceFactory extends UnpooledDataSourceFactory {

  public PooledDataSourceFactory() {
    this.dataSource = new PooledDataSource();
  }

}

装饰者模式

在这里插入图片描述
在这里插入图片描述

组合模式

封装成树

public class XMLScriptBuilder extends BaseBuilder {
  public SqlSource parseScriptNode() {
    //首先判断当前的节点是不是有动态SQL ,动态SQL 会包括占位符或是动态SQL 的相关节点
    MixedSqlNode rootSqlNode = parseDynamicTags(context);
    SqlSource sqlSource;
    //根据是否是动态SQL , 创建相应的SqlSource 对象
    if (isDynamic) {
      sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
    } else {
      sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);
    }
    return sqlSource;
  }
protected MixedSqlNode parseDynamicTags(XNode node) {
    //用于记录生成的SqlNode 集合
    List<SqlNode> contents = new ArrayList<>();
    //获取SelectKey 的所有子节点
    NodeList children = node.getNode().getChildNodes();
    for (int i = 0; i < children.getLength(); i++) {
      //创建XNode ,该过程会将能解析掉的” ${} ” 都解析掉
      XNode child = node.newXNode(children.item(i));
      if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
        String data = child.getStringBody("");
        TextSqlNode textSqlNode = new TextSqlNode(data);
        //解析SQL 语句,如果含有未解析的”${}”占位符,则为动态SQL
        if (textSqlNode.isDynamic()) {
          contents.add(textSqlNode);
         // 标记为动态SQL 语句
          isDynamic = true;
        } else {
          contents.add(new StaticTextSqlNode(data));
        }
      } else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628
        //如果子节点是一个标签,那么一定是动态SQL ,并且根据不同的动态标签生成不同的NodeHandler
        String nodeName = child.getNode().getNodeName();
        //根据标签名称获取对应 的NodeHandler 对象
        //处理where之类
        NodeHandler handler = nodeHandlerMap.get(nodeName);
        if (handler == null) {
          throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
        }
        //处理动态SQL ,并将解析得到的SqlNode 对象放入contents 集合中保存
        handler.handleNode(child, contents);
        isDynamic = true;
      }
    }
   // SqlNode 集合包装成一个MixedSqlNode
    return new MixedSqlNode(contents);
  }
  }
public class MixedSqlNode implements SqlNode {
  private final List<SqlNode> contents;

  public MixedSqlNode(List<SqlNode> contents) {
    this.contents = contents;
  }

  @Override
  public boolean apply(DynamicContext context) {
    contents.forEach(node -> node.apply(context));
    return true;
  }
}
public class DynamicSqlSource implements SqlSource {
  @Override
  public BoundSql getBoundSql(Object parameterObject) {
    // 创建DynamicContext 对象, parameterObject 是用户传入的实参
    DynamicContext context = new DynamicContext(configuration, parameterObject);
    //通过调用rootSqlNode.apply ()方法调用整个树形结构中全部SqlNode. apply ()方法,读者可以
// 体会一下组合设计模式的好处。每个SqlNode 的apply ()方法都将解析得到的SQL 语句片段追加到
    // context 中, 最终通过context.getSql()得到完整的SQL 语句
    rootSqlNode.apply(context);
    //创建SqlSourceBuilder ,解析参数属性,并将SQL 语句中的”#{ ) ” 占位符替换成” ? ” 占位符
    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
    SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
    //创建BoundSql 对象,并将DynamicContext.bindings 中的参数信息复制到其additionalParameters 集合中保存
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    context.getBindings().forEach(boundSql::setAdditionalParameter);
    return boundSql;
  }

}

策略模式

策略模式一

public class RoutingStatementHandler implements StatementHandler {
//底层封装的真正的StatementHandler 对象
  private final StatementHandler delegate;

  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

  }
  }

策略模式二

在这里插入图片描述
摸吧在这里插入图片描述

模板模式

交给子类实现
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值