序文
Spring フレームワークは、Java エンタープライズ アプリケーションで最も一般的に使用されるフレームワークの 1 つであり、豊富なアプリケーション開発機能を提供することで、開発者はエンタープライズ アプリケーションを簡単に作成できます。その中でも、Spring AOP は Spring フレームワークの重要な部分です。この記事では、Spring AOP とは何か、Spring AOP の実装原理、JDK ダイナミック プロキシ、CGLIB ダイナミック プロキシなど、Spring AOP の実装原理を詳しく紹介します。
Spring AOPとは何ですか?
Spring AOP は Spring フレームワークの主要なモジュールであり、アスペクト指向プログラミング (AOP) を実装し、これに基づいて横断的な問題に対するいくつかの一般的なソリューションを提供します。ビジネスとは関係がないものの、アプリケーション全体に絡み合っているトランザクションを一元管理できるため、懸念事項があちこちに分散するのではなく分離されます。
Spring AOPの実装原理
Spring AOP の中核となるメカニズムはプロキシ モードです。プロキシ パターンでは、プロキシ オブジェクトが実際のビジネス オブジェクトへのアクセスを制御し、その動作を拡張します。Spring AOP は、JDK 動的プロキシと CGLIB 動的プロキシの 2 種類のプロキシを提供します。
JDK動的プロキシ
JDK ダイナミック プロキシは、Java 言語によって提供される動的プロキシの実装方法です。プロキシ オブジェクトを作成するために JDK によって提供される java.lang.reflect.Proxy クラスを使用して、ターゲット オブジェクトが 1 つ以上のインターフェイスを実装する必要があります。JDK 動的プロキシには主に、InvocationHandler と Proxy の 2 つのクラスが含まれます。InvocationHandler はプロキシ オブジェクトのコールバック メソッドであり、Proxy はプロキシ オブジェクトを作成するためのファクトリ クラスです。プロキシ オブジェクトのメソッドが呼び出されると、JDK 動的プロキシはメソッド呼び出しを InvocationHandler にディスパッチし、メソッド呼び出しの前後にいくつかの拡張操作を実行します。
CGLIB 動的プロキシ
CGLIB ダイナミック プロキシは、もう 1 つの一般的なプロキシ パターン実装です。JDK 動的プロキシとは異なり、CGLIB 動的プロキシは、インターフェイスを実装せずに任意のクラスをプロキシできます。CGLIB 動的プロキシは、ターゲット クラスを継承してそのメソッドを書き換えることによってプロキシを実装し、メソッド呼び出しの前後にいくつかの拡張操作を実行します。
CGLIB は、ASM (Java バイトコード操作および分析フレームワーク) に基づく 2 次カプセル化であり、バイトコードを直接操作して、対応する動的プロキシ クラスを生成します。JDK 動的プロキシとは異なり、CGLIB によって生成されるプロキシ クラスはターゲット クラスのサブクラスです。したがって、CGLIB はターゲット クラス プロキシを迅速に呼び出すことができ、JDK 動的プロキシよりも効率的です。
以下に、CGLIB の実装原理を簡単に紹介します。
CGLIB プロキシ実装プロセス
CGLIB プロキシの実装は、インターフェイスを実装するクラスのみをプロキシできる JDK 動的プロキシとは異なり、実行時にターゲット クラスのサブクラスをプロキシ オブジェクトとして生成するバイトコード テクノロジに基づいています。CGLIB プロキシの実装手順は次のとおりです。
-
CGLIB の中核となるエンハンサー オブジェクトを作成します。このオブジェクトは、ターゲット クラスのサブクラスを動的に作成するために使用されます。
-
setSuperclass() メソッドを通じてターゲット クラスを設定すると、エンハンサーはターゲット クラスのサブクラスをプロキシ オブジェクトとして動的に生成します。
-
setCallBack() メソッドを通じてコールバック関数を設定します。プロキシ オブジェクトが呼び出されると、CGLIB は呼び出しをインターセプトし、処理のために Callback インターフェイスを実装するクラスに転送します。
-
create() メソッドを呼び出して、プロキシ クラスのインスタンスを生成します。
CGLIB がターゲット クラスのサブクラスを生成すると、ターゲット クラス内のすべての非 Final メソッドおよび非プライベート メソッドに対して MethodInterceptor オブジェクトが作成されます。これには、プロキシ クラスが織り込む必要があるロジックが含まれます。CGLIB は、動的プロキシのパフォーマンスを向上させるために FastClass メカニズムを使用しており、実行時にバイトコードに直接アクセスできるため、リフレクションのオーバーヘッドが回避されます。プロキシ クラスが呼び出されると、CGLIB は FastClass の getIndex() メソッドを呼び出してプロキシ メソッドのインデックスを取得し、次に invoke() メソッドを呼び出して対応するプロキシ ロジックを実行します。
CGLIB プロキシ インスタンス
以下は、簡単な CGLIB プロキシ インスタンス コードです。これは、エンハンサを通じてターゲット クラスのサブクラスを動的に作成することでプロキシを実装します。
public class UserDao {
public void save() {
System.out.println("保存用户信息");
}
}
public class UserDaoInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("事务开始...");
Object result = methodProxy.invokeSuper(o, args);
System.out.println("事务结束...");
return result;
}
}
public class CglibTest {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserDao.class);
enhancer.setCallback(new UserDaoInterceptor());
UserDao userDao = (UserDao) enhancer.create();
userDao.save(); // 输出:事务开始...保存用户信息事务结束...
}
}
上記のコードでは、UserDaoInterceptor クラスが MethodInterceptor インターフェイスを実装し、intercept() メソッドを書き換えます。プロキシ クラスのメソッドが呼び出されると、CGLIB は呼び出しをインターセプトし、処理のために UserDaoInterceptor に転送します。一部のアスペクト ロジックはこのメソッドで完了できます。
要約する
Spring AOP は、プロキシ モードを通じて横断的な懸念の分離を実現し、コードの保守性と再利用性を向上させます。JDK 動的プロキシと CGLIB 動的プロキシは、Spring AOP の 2 つのコア実装です。どのアプローチを使用するかの選択は、ビジネス要件と技術的な制約によって異なります。Spring AOP を使用する場合、それを正しく使用して問題を解決するには、その実装原理を明確に理解する必要があります。