モジュールのパースを解析するMyBatisのソース:ログモジュール

入門

MyBatisの実装クラスは、第三のコンポーネントのニーズへのアクセスをログに記録し、ログを提供していませんでした

第三のクラスへのコードの静的たLogFactoryブロックは、負荷優先ログSLF4Jとして見ることができ> Apacheのコモンズ> log4j2> log4jの> 7月ログ

  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();
      }
    });
	
	// 省略了其他模块的加载逻辑
  }

工場出荷時のパターンで使用したLogFactoryクラス名からわかるように、工場出荷時のパターンを使用すると、以下の記事を見ることができます理解していません

ファクトリーモード(staticファクトリパターン、Factory Methodパターン、Abstract Factoryパターン)コメント

しかし、第三者が、MyBatisのアダプタは、統合モデルトレース、デバッグを提供し、自分の対数を持って警告し、4つのレベルのエラー

org.apache.ibatis.logging.Logインタフェースは、複数の実装クラス、アダプタによってMyBatisのが設けられている実装クラス有する
アダプタクラス、のようなUMLクラス図以下、実装を提供し、例えばLog4jImpl、Log4j2Implを

ここに画像を挿入説明

オブジェクト上記ロガー図は、すなわち、変換の操作によりLog4jImplログインタフェースは、操作対象ロガーに適合し、org.apache.log4j.Loggerあります

アダプタパターン設計は、いくつかの役割を次の

  1. ターゲット・インタフェース(ターゲット):発信者インターフェイスはインターフェイスログ、すなわち、直接使用することができ
  2. アダプタの必要なクラス(Adaptee):Adapteeクラスは、実際の論理を持っていますが、呼び出し側がいることを、直接使用することはできませんLoggerオブジェクト
  3. アダプタ(アダプタ):ターゲットインタフェースを実装するには、Adapteeオブジェクトを詰め

もちろん、我々は一般的にレベルが低すぎるため、INFOレベルではなく、プロジェクト内のMyBatisのフィット後Loggerオブジェクトを設定していません

import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
public static final Log log = LogFactory.getLog(Test.class);

SLF4Jを導くように構成されました

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public static final Logger logger = LoggerFactory.getLogger(Test.class);

すべての適応に、JDBCモジュールはログを出力しますので、それが結合して、特定のロギングフレームワーク、MyBatisの適応後Logオブジェクトを使用していません

JDBCのデバッグ、ログの種類を印刷します

MyBatisの源で、その出力DEBUGレベルに、このようなSQL文、渡されるユーザパラメータバインディングの出力のような動的な方法薬、で多くの有用な情報をロギングモジュールJDBCパッケージ、ログレベルを有し、行の数と同じように、SQL文に影響を与えます情報

あなたはなぜ動的プロキシを通してそれをデバッグレベルのログを印刷する必要があり、思考かもしれませんか?log.debug付()リストに、主に対数正規のロジックを回避し、ロジックに結合されていません

BaseJdbcLoggerは、相続次の図のJDBCパッケージの下に他のLoggerクラスの親である抽象クラスである
ここに画像を挿入説明
接続情報とSQL文を印刷するための責任、およびPreparedStatementLogger作成:ConnectionLogger
PreparedStatementLoggerを:パラメータ情報を印刷するための責任、およびResultSetLogger作成
StatementLoggerを:パラメータを印刷するための責任情報、およびResultSetLogger作成
ResultSetLoggerを:データ結果の情報を印刷するための責任

考え方は同じである4クラスが実装ただConnectionLoggerを分析するために、

デバッグログレベルは、そうでない場合は通常の接続オブジェクトは、プロキシされた後、Connectionオブジェクトを返す場合

  protected Connection getConnection(Log statementLog) throws SQLException {
    Connection connection = transaction.getConnection();
    if (statementLog.isDebugEnabled()) {
      return ConnectionLogger.newInstance(connection, statementLog, queryStack);
    } else {
      return connection;
    }
  }

ConnectionLoggerのInvocationHandlerオブジェクトがインタフェースを実装して、エージェントは、Connectionオブジェクトの後に返さ

  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);
  }

次のように具体的な傍受ロジックがあります

  @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的方法,打印要执行的SQL语句
      // 并返回PreparedStatement的代理对象,让PreparedStatement也具备日志能力,打印参数
      if ("prepareStatement".equals(method.getName())) {
        if (isDebugEnabled()) {
          debug(" Preparing: " + removeBreakingWhitespace((String) params[0]), true);
        }        
        PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params);
        stmt = PreparedStatementLogger.newInstance(stmt, statementLog, queryStack);
        return stmt;
      } else if ("prepareCall".equals(method.getName())) {
        if (isDebugEnabled()) {
          debug(" Preparing: " + removeBreakingWhitespace((String) params[0]), true);
        }        
        PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params);
        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);
    }
  }

私たちは三つの方法がのprepareStatement、のprepareCall、のcreateStatementを強化して見ることができます

メソッドが実行されるのprepareStatement、のprepareCall SQLステートメントの呼び出すことであれば、印刷
のPreparedStatementも、印刷パラメータを記録する能力を持っているので、3つの方法が、プロキシオブジェクトPreparedStatementを返します。

最終的な印刷DEBUGログを参照してください。

DEBUG 2020-02-24 18:09:13,647 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select id, `name`, phone from author 
DEBUG 2020-02-24 18:09:13,766 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 
DEBUG 2020-02-24 18:09:13,813 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1

精通見ていない、それが達成するために、動的プロキシを使用することです

注意ようこそ

ここに画像を挿入説明

公開された385元の記事 ウォンの賞賛1471 ビュー90万+

おすすめ

転載: blog.csdn.net/zzti_erlie/article/details/104398887