MybatisはSQLクエリのインターセプションと変更の詳細を実装します

MybatisはSQLクエリのインターセプションと変更の詳細を実装します

序文

インターセプターの機能の 1 つは、特定のメソッドの呼び出しをインターセプトできることです。インターセプトされたメソッドの実行の前後にロジックを追加することも、インターセプトされたメソッドを実行する代わりに、インターセプトされたメソッドを実行するときに独自のロジックを実行することもできます。

Mybatis インターセプターを設計した当初の目的の 1 つは、Mybatis の固有のロジックを変更することなく、ユーザーが特定のタイミングで独自のロジックを実装できるようにすることです。たとえば、すべての SQL に対して固定操作を実行したり、SQL クエリに対してセキュリティ チェックを実行したり、関連する SQL クエリ ログを記録したりしたいとします。

Mybatis は、カスタム インターセプターを実装できる Interceptor インターフェースを提供します。

 パブリックインターフェースインターセプター{
 オブジェクト intercept(Invocation invocation) は Throwable をスローします。
 オブジェクトプラグイン(オブジェクトターゲット);
 void setProperties(プロパティプロパティ);
}

インターフェースには3つのメソッド定義が含まれています

インターセプトメソッドは、インターセプトオブジェクトに対する特定の処理メソッドです。渡される Invocation には、インターセプト対象クラスの強度、インターセプトメソッド、およびメソッドの入力パラメータグループが含まれます。呼び出し手順を使用して元の関数を実行します。

プラグインはインターセプトするかどうかを決定します。インターセプトが不要な場合は、ターゲットが直接返されます。インターセプトが必要な場合は、Plugin クラスの wrap 静的メソッドが呼び出されます。現在のインターセプターがインターフェイスを実装している場合はプロキシ オブジェクトが返され、そうでない場合は直接返されます (プロキシ モードの設計を思い出してください)。プロキシ オブジェクトは、実際には InvocationHandler インターフェイスを実装する Plugin クラスのインスタンスです。InvocationHandler インターフェイスには、コールバック メソッドの呼び出しメソッドのみが含まれます。

プロキシ オブジェクトのインターフェイス メソッドが実行されると、プラグインの呼び出しメソッドが呼び出され、実行されるオブジェクト、メソッド、およびパラメーターが呼び出しオブジェクトにパッケージ化され、インターセプターのインターセプト メソッドに渡されます。呼び出しは、インターセプトされた元のメソッドを実行するための procced メソッドを定義します。

プラグインクラスの定義

パブリッククラスPluginはInvocationHandlerを実装します{
 
 プライベートオブジェクトターゲット;
 プライベートインターセプターインターセプター;
 プライベート Map、Set> signatureMap;
 
 プライベートプラグイン(オブジェクトターゲット、インターセプターインターセプター、マップ、Set> signatureMap) {
  this.target = ターゲット;
  this.interceptor = インターセプター;
  this.signatureMap = 署名マップ;
 }
 
 パブリック静的オブジェクトラップ(オブジェクトターゲット、インターセプターインターセプター) {
  マップ、セット> signatureMap = getSignatureMap(インターセプター);
  クラスタイプ = target.getClass();
  クラス[]インターフェース = getAllInterfaces(type, signatureMap);
  インターフェースの長さが0より大きい場合
   Proxy.newProxyInstance() を返します。
     type.getClassLoader()、
     インターフェース、
     新しいプラグイン(ターゲット、インターセプター、シグネチャマップ));
  }
  ターゲットを返します。
 }
 
 パブリックオブジェクトinvoke(オブジェクトプロキシ、メソッドメソッド、オブジェクト[]引数)throwsThrowable{
  試す {
   メソッドを signatureMap.get(method.getDeclaringClass()); に設定します。
   メソッドが null の場合、methods.contains(method) は次のように記述されます。
    interceptor.intercept(new Invocation(target, method, args)) を返します。
   }
   メソッドを呼び出します(ターゲット、引数)。
  } キャッチ (例外 e) {
   ExceptionUtil.unwrapThrowable(e) をスローします。
  }
 }
 
 プライベート静的マップ、Set> getSignatureMap(インターセプターインターセプター) {
  インターセプト interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
  if (interceptsAnnotation == null) { // 問題 #251
   throw new PluginException("インターセプターに @Intercepts アノテーションが見つかりません " + interceptor.getClass().getName());   
  }
  署名[] sigs = interceptsAnnotation.value();
  Map、Set> signatureMap = new HashMap、Set>();
  (署名 sig : sigs) {
   メソッドを設定します = signatureMap.get(sig.type());
   if (メソッド == null) {
    メソッド = 新しい HashSet();
    signatureMap.put(sig.type(), メソッド);
   }
   試す {
    メソッド method = sig.type().getMethod(sig.method(), sig.args());
    メソッドを追加します。
   } キャッチ (NoSuchMethodException e) {
    throw new PluginException("" + sig.type() + " に " + sig.method() + " という名前のメソッドが見つかりませんでした。原因: " + e, e);
   }
  }
  署名マップを返します。
 }
 
 プライベート静的Class[] getAllInterfaces(クラス型、マップ、セット> signatureMap) {
  Set> インターフェース = new HashSet>();
  while (type != null) {
   (クラスcの場合: type.getInterfaces()) {
    署名マップにキーが含まれている場合(c)
     インターフェースを追加します。
    }
   }
   タイプ = type.getSuperclass();
  }
  戻り値:interfaces.toArray(新しいClass[interfaces.size()]);
 }
 
}

setProperties メソッドは、その名前が示すように、プロパティを設定するために使用されます。 Bean プロパティを初期化する方法は多数ありますが、これはその 1 つです。

Mybatis は、現在のクラスがインターセプターであることを宣言するための @Intercepts アノテーションを提供します。その値は @Signature 配列であり、インターセプトされるインターフェース、メソッド、および対応するパラメーター タイプを示します。

@Intercepts({@Signature(メソッド = "準備"、タイプ = StatementHandler.class、引数 = {Connection.class})、
    @Signature(メソッド = "query"、タイプ = StatementHandler.class、引数 = {java.sql.Statement.class、ResultHandler.class})})
パブリッククラス TenantInterceptor は Interceptor を実装します {
.....

たとえば、上記のクラス宣言では、最初の Signature アノテーションは StatementHandler クラスの下にある入力パラメータ (prepare という名前の Connection メソッド) をインターセプトします。

2 番目の Signature アノテーションは、2 つの入力パラメータ (Statement 型と ResultHandler 型) を含む StatementHandler クラスのクエリ メソッドをインターセプトします。

最後に、宣言された Interceptor を有効にするには、mybatis プラグに登録する必要があります。

  <!-- mybatis を設定する -->
  <bean id="sqlSessionFactory" クラス="org.mybatis.spring.SqlSessionFactoryBean">
    <プロパティ名="データソース" ref="データソース"/>
    <プロパティ名="configLocation" 値="classpath:mybatis/mybatis-config.xml"/>
    <!-- マッパースキャン -->
    <プロパティ名="mapperLocations" 値="classpath:mybatis/*/*.xml"/>
    <プロパティ名="プラグイン">
      <配列>
        <!-- 独自のインターセプターを登録する -->
        <bean id="paginationInterceptor" class="xxx.xxx.TenantInterceptor">
        </bean>
      </配列>
    </プロパティ>
  </bean>

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • Mybatis で SQL クエリに複数のパラメータを渡す方法
  • Mybatis の SQL ノードの詳細な分析

<<:  実際のプロジェクトでElementUIを使用する手順の詳細な説明

>>:  Vue 仮想 Dom から実際の Dom への変換

推薦する

JavaScriptで継承を実装するいくつかの方法

目次構造継承(callで実装)プロトタイプチェーン継承(プロトタイプチェーンの助けを借りて実装)複合...

一般的な Linux ツール vi/vim の完全版

なぜvimを学ぶのかLinuxには多数の設定ファイルがあるため、Linuxには多くのテキスト処理ツー...

Vue.jsはElement-uiを使用してナビゲーションメニューを実装します

この記事では、Element-uiを使用してvue.jsでナビゲーションメニューを実装するための具体...

React.Childrenの詳しい使い方

目次1. React.Children.map 2. React.Children.forEach ...

MySQLのunion allとunionの違いを簡単に理解する

Union は、重複行を除外し、デフォルトのソートを実行する、データに対する結合操作です。Union...

Zabbixについて管理者ログインパスワードを忘れた場合、パスワードをリセットする

Zabbix 管理者ログイン パスワードのリセットに関する問題は次のとおりです。 1. 問題の説明:...

Javascript Echarts 空気質マップ効果の詳細な説明

まず、空気質データと地図データを組み合わせる必要があります。マップデータには属性名があるさまざまな都...

MySQL テーブル作成外部キー エラーの解決方法

データベーステーブルA: テーブル task_desc_tab を作成します ( id INT(11...

Reactのようなフレームワークをゼロから作成する

最近、インターネットで「Build your own React」という記事を見ました。著者は、シン...

ES6拡張演算子の理解と使用シナリオ

目次1. 適用メソッドを置き換え、関数を呼び出すときにパラメータを処理する2. 残りパラメータ(残り...

PrometheusとGrafanaを使用したMySQLサーバーのパフォーマンス監視の詳細な説明

概要Prometheus は、HTTP プロトコルを介してリモート マシンからデータを収集し、ローカ...

MySQL 実行ステータスの表示と分析

MySQL のパフォーマンスに問題があると思われる場合は、通常、まずshow processlist...

垂直方向の中央揃えをエレガントに実現する方法を教えます(推奨)

序文CSS で水平方向と垂直方向に中央揃えする方法はたくさんあります。この記事で紹介する方法は非常に...

Centos8環境でSSHポート番号を変更する方法

目次序文始める序文サーバーのデフォルトの SSH ポート番号は通常 22 であるため、ほとんどのユー...

Reactを使用する際の7つの落とし穴のまとめ

目次1. コンポーネントの肥大化2. 状態を直接変更する3. プロパティは数値を渡す必要があるが文字...