Springを学ぶとき、Springには2つの主要なアイデアがあることを知っています。1つはIoCで、もう1つはAOPです。IoCの場合、依存性注入は多くのことを言う必要はありません。SpringのコアAOPの場合、渡す方法を知るだけでなく機能を満たすためにAOPを使用するには、基礎となる原理についてさらに学ぶ必要があります。AOPの原理はJavaの動的プロキシメカニズムであるため、このエッセイはJavaの動的メカニズムのレビューです。
Javaの動的プロキシメカニズムには、2つの重要なクラスまたはインターフェイスがあります。1つはInvocationHandler(インターフェイス)、もう1つはプロキシ(クラス)です。このクラスとインターフェイスは、動的プロキシを実現するために必要です。最初に、Java APIヘルプドキュメントでこれらの2つのクラスがどのように記述されているかを見てみましょう。
InvocationHandler:
InvocationHandlerは、プロキシインスタンスの呼び出しハンドラによって実装されるインターフェースです。
各プロキシインスタンスには、関連付けられた呼び出しハンドラがあります。メソッドがプロキシインスタンスで呼び出されると、メソッド呼び出しはエンコードされ、その呼び出しハンドラのinvokeメソッドにディスパッチされます。
各動的プロキシクラスはInvocationHandlerインターフェイスを実装する必要があり、プロキシクラスの各インスタンスはハンドラに関連付けられています。プロキシオブジェクトを介してメソッドを呼び出すと、メソッド呼び出しはInvocationHandlerのインターフェイスに転送されますinvokeメソッドを呼び出す。InvocationHandlerのインターフェースの唯一のinvokeメソッドを見てみましょう:
Object invoke(Object proxy、Method method、Object [] args)throws Throwable
このメソッドは合計3つのパラメーターを受け入れることがわかります。したがって、これらの3つのパラメーターは何を表していますか?
オブジェクト呼び出し(オブジェクトプロキシ、メソッド方法,,オブジェクト[]引数)がスローのThrowable プロキシ: 我々は薬剤である実際のオブジェクトを参照して、方法: 我々は実際のオブジェクトのメソッド呼び出したいメソッドのオブジェクトを指す引数を: を指し実際のオブジェクトでメソッドを呼び出すときにパラメーターは受け入れられますか
理解できない場合は、例を使用してこれらのパラメータについて詳しく説明します。
次に、Proxyクラスを見てみましょう。
プロキシは、動的プロキシクラスとインスタンスを作成するための静的メソッドを提供し、これらのメソッドによって作成されたすべての動的プロキシクラスのスーパークラスでもあります。
Proxyクラスの役割は、多くのメソッドを提供するプロキシオブジェクトクラスを動的に作成することですが、最もよく使用するのはnewProxyInstanceメソッドです。
public static Object newProxyInstance(ClassLoader loader、Class <?> [] interfaces、InvocationHandler h) が IllegalArgumentExceptionをスローする
戻るプロキシのインスタンスのクラス のために指定された呼び出しハンドラに対してメソッド呼び出しをディスパッチする、指定されたインタフェース。
このメソッドの役割は、3つのパラメーターを受け取る動的プロキシオブジェクトを取得することです。これら3つのパラメーターの意味を見てみましょう。
パブリック 静的オブジェクトのnewProxyInstance(クラスローダローダ、クラス[]のInvocationHandler Hのインターフェース、<?>)スローはIllegalArgumentException ローダ: ClassLoaderオブジェクトは、クラスローダは、オブジェクトそれによって生成されたプロキシオブジェクトをロードするために定義されたインタフェースを: インタフェースが表すオブジェクトの配列を私が欲しいのは、プロキシする必要のあるオブジェクトに一連のインターフェースを提供することです。それに一連のインターフェースを提供すると、プロキシオブジェクトはインターフェースを実装すると主張し(多態性)、このインターフェースのセットを呼び出すことができます。メソッドはh: InvocationHandlerオブジェクトで、動的プロキシオブジェクトがメソッドを呼び出すときにどのInvocationHandlerオブジェクトが関連付けられるかを示します。
さて、これらの2つのインターフェース(クラス)を紹介した後、例を見て、動的プロキシモデルがどのように見えるかを見てみましょう。
まず、Subject型のインターフェースを定義し、そのための2つのメソッドを宣言します。
public interface Subject { public void rent(); public void hello(String str); }
次に、このインターフェイスを実装するクラスを定義します。このクラスは、実際のオブジェクトであるRealSubjectクラスです。
パブリック クラス RealSubject はサブジェクトを 実装します { @Override public void rent() { System.out.println( "自分の家を借りたい" ); } @Override public void hello(String str) { System.out.println( "hello:" + str); } }
次に、動的プロキシクラスを定義する必要があります前述のように、各動的プロキシクラスはInvocationHandlerインターフェイスを実装する必要があるため、動的プロキシクラスも例外ではありません。
public class DynamicProxy implements InvocationHandler { // これは、プロキシする実際のオブジェクトです private Object subject; // 構築メソッド、プロキシする実際のオブジェクトに初期値を割り当てます public DynamicProxy(Object subject) { this .subject = subject; } @ public Object invoke(Object object、Method method、Object [] args)をオーバーライドします throws Throwable { // 実際のオブジェクトをプロキシする前に独自の操作の一部を追加できます System.out.println( "before rent house" ); System.out。 println( "メソッド:" + メソッド); // プロキシオブジェクトのメソッドは、実際のオブジェクトを呼び出すようにすると、それが自動的に呼び出すためのプロキシオブジェクトに関連付けられているオブジェクトのメソッド・ハンドラを呼び出すためにジャンプします Method.invoke(件名、引数を); // エージェント実際のオブジェクトの後に、我々はまた、いくつかを追加することができます独自の操作 System.out.println( "after rent house" ); 戻り値 null ; } }
最後に、Clientクラスを見てみましょう。
public class Client { public static void main(String [] args) { // プロキシしたい実際のオブジェクト Subject realSubject = new RealSubject(); // プロキシしたい実際のオブジェクト、オブジェクトを渡し、最後に渡しますメソッドを呼び出す実際のオブジェクト InvocationHandler handler = new DynamicProxy(realSubject); / * *プロキシのnewProxyInstanceメソッドでプロキシオブジェクトを作成します。3つのパラメータを見てみましょう *最初のパラメータhandler.getClass() .getClassLoader()、ハンドラクラスのClassLoaderオブジェクトを使用してプロキシオブジェクトをロードします * 2番目のパラメータrealSubject.getClass()。getInterfaces()、プロキシオブジェクト用にここで提供するインターフェイスは、実際のオブジェクトによって実装されるインターフェイスです、実際のオブジェクトをプロキシし、このインターフェイスのセットのメソッドを呼び出すことができることを示します * 3番目のパラメーターハンドラー。このプロキシオブジェクトを上記のInvocationHandlerオブジェクトに関連付けます * / サブジェクトサブジェクト =(Subject)Proxy.newProxyInstance(handler.getClass()。getClassLoader()、realSubject .getClass()。getInterfaces()、handler); System.out.println(subject.getClass()。getName()); subject.rent(); subject.hello( "world" ); } }
最初にコンソールの出力を見てみましょう:
家を借りる前の$ Proxy0 メソッド:public abstract void com.xiaoluo.dynamicproxy.Subject.rent() 家 を借りる 前に家を借りた後、家を借りたい メソッド:public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java。 lang.String) hello: 家を借りた後の世界
最初に$ Proxy0を見てみましょう。これはSystem.out.println(subject.getClass()。GetName())によって出力されることがわかります。これが、このプロキシオブジェクトを返した理由です。クラス名はこんな感じ?
件名件名= (Subject)Proxy.newProxyInstance(handler.getClass()。getClassLoader()、realSubject
.getClass()。getInterfaces()、handler);
返されたプロキシオブジェクトは、Subject型のオブジェクト、またはInvocationHandlerのオブジェクトであると思ったかもしれませんが、結果はそうではありません。最初に、なぜここでSubject型のオブジェクトに変換できるのかを説明しましょう。その理由は、newProxyInstanceメソッドの2番目のパラメーターで、プロキシオブジェクトのインターフェイスのセットを提供し、プロキシオブジェクトがこのインターフェイスのセットを実装するためです。現時点では、プロキシオブジェクトを必須の型変換に変換できます。このグループのインターフェースのいずれか1つでは、ここのインターフェースはサブジェクトタイプであるため、サブジェクトタイプに変換できます。
同時に、Proxy.newProxyInstanceによって作成されたプロキシオブジェクトは、jvmの実行中に動的に生成されるオブジェクトであることを覚えておく必要があります。これは、InvocationHandlerタイプでも定義したインターフェースグループのタイプでもありませんが、実行中です。動的に生成されたオブジェクト。命名方法はこの形式で、$で始まり、プロキシがあり、最後の数字はオブジェクトのラベルを示します。
次に、これらの2つの文を見てみましょう
subject.rent();
subject.hello( "world");
プロキシオブジェクトを介して実装された種類のインターフェイスのメソッドは次のとおりです。このとき、プログラムはプロキシオブジェクトに関連付けられたハンドラーのinvokeメソッドにジャンプして実行し、ハンドラーオブジェクトはRealSubjectを受け入れます。 typeパラメーターは、プロキシするのがこの実際のオブジェクトであることを示しているため、この時点で、ハンドラーのinvokeメソッドが呼び出されて実行されます。
public Object invoke(Object object、Method method、Object [] args) throws Throwable { // 実際のオブジェクトをプロキシする前に独自の操作の一部を追加できます System.out.println( "before rent house" ); System.out.println (「方法,:」+ 方法); // プロキシオブジェクトのメソッドを呼び出したときに自動的にコールにプロキシオブジェクト・ハンドラに関連付けられたメソッドを呼び出すためにジャンプする実際のオブジェクトは、オブジェクト Method.invoke(件名、引数); / / 実際のオブジェクトをプロキシした後、独自のオペレーション System.out.println( "after rent house" );を 返す こともできます; nullを返す; }
実際のオブジェクトのメソッドがプロキシオブジェクトを介して呼び出されると、メソッドの前後に独自の操作の一部を追加でき、メソッドオブジェクトは次のようになります。
public abstract void com.xiaoluo.dynamicproxy.Subject.rent() public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)
これは、Subjectインターフェースの2つのメソッドですが、これは、プロキシオブジェクトを介してメソッドを呼び出すと、自分ではなく、関連付けられているハンドラーオブジェクトのinvokeメソッドによって呼び出されるように委譲されていることを示しています。実際の通話ですが、エージェントを介して通話します。
これは私たちのJava動的プロキシメカニズムです
このエッセイでは、Javaの動的プロキシメカニズムについて詳しく説明していますが、動的プロキシメカニズムを通じて実装されるSpring AOPを含め、この知識ポイントは非常に重要なので、動的プロキシメカニズムをよく理解する必要があります。