小言_互联网的博客

mybatis源码解析五之设计模式

312人阅读  评论(0)

单例模式

利用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();
  }

}

转载:https://blog.csdn.net/Nuan_Feng/article/details/106003554
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场