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 への変換

推薦する

Nginx 正規表現関連のパラメータとルールの紹介

序文最近、私はクライアントのサーバー構成を支援しており、Nginx 構成ファイルを頻繁に変更していま...

IP アドレス経由で MySql にアクセスする方法

1. mysqlにログインします。 mysql -u ルート -h 127.0.0.1 -p 2. ...

HTML 縦列表示テキストを使用してテキストを縦列で表示します

コードをコピーコードは次のとおりです。 <span style='display:bl...

MySQLでインデックスエラーが発生する状況について簡単に説明します

以下に、トレーニング機関からのヒントと私自身の要約をいくつか示します。以下のインデックスの内容を説明...

nginx のロケーションで URI の傍受を実装する方法

例:場所のルートとエイリアスルートディレクティブは、ルートによって設定されたディレクトリに検索ルート...

DockerはPruneコマンドを使用してnoneイメージをクリーンアップします

目次無イメージの創造と混乱Noneオブジェクトをクリーンアップする方法トリムミラーコンテナで使用され...

docker.service 起動エラーの詳細なトラブルシューティング

エラーを報告するには次のコマンドを実行しますsystemctl dockerを再起動しますエラーメッ...

SQLと各種NoSQLデータベースの使用シナリオの説明

SQL はメイントランクです。なぜ私はこのように理解するのでしょうか。技術的な観点からリレーショナル...

Unicode署名BOMによる事故原因の分析

ここでは、通常ヘッダーとフッターに対して行われるインクルード ファイルを使用している可能性があります...

効率的な視覚化Nginxログ表示ツール

目次導入インストール表示フィールドフィルターソートキー導入Rhit は、標準フォルダー (gzip ...

ReactアプリケーションにおけるDOM DIFFアルゴリズムの詳細な説明

目次序文VirtualDOM とは何ですか? VirtualDOMを使用する理由DOMレンダリングペ...

フロントエンド開発に必須:推奨されるブラウザ互換性テストツール 12 選

フロントエンド開発者にとって、さまざまな主要ブラウザのさまざまなバージョンでコードが適切に動作するこ...

CSS は Google マテリアル デザインのテキスト入力ボックス スタイルを実装します (推奨)

みなさんこんにちは。今日は、純粋な CSS を使用して Google マテリアル デザインのテキスト...

MySQL バックアップ スクリプトの書き方

序文:データベースのバックアップの重要性は、特にデータの損失が深刻な結果を招く可能性がある実稼働環境...

Navicat が MySql サーバーにリモート接続できない問題の解決策

Navicat が MySql サーバーにリモート接続できない問題の解決策は、先頭に書かれています:...