私はJavaのオブジェクト指向(OOP)、オブジェクト指向のいくつかの公共の行為では、ログのような、などをお話しましょう、あなたが行うには、オブジェクト指向の使用を検証する権限を持っている場合は、各ビジネス・プロセス内の重複コードを記述する必要があります、垂直抽出機構は、冗長コードが得られ、解決します。水平抽出機構を使用して、AOP指向プログラミング、ソースコードを変更せずに実現拡張機能を指します。対応する方法を切断するセクションによって定義されたセクションは、関連するロジックに織ることができます。基本的なダイナミックプロキシモードとAOP。
まず、プロキシモード
プロキシ公式の定義を比較した23の古典的なデザインパターンの一つとして、モデルはAクラスの前に、ある単純なポイント「このオブジェクトへのアクセスを制御するために、他のオブジェクトのプロキシを提供すること」である自分は一つのこと、の使用エージェントの後、クラスが直接ませんが、プロキシクラスBクラスによって行われます。実際には、クラスの前にプロキシクラスは、レイヤパッケージをやってに基づいています。帯電防止剤でJava、JDKの動的プロキシ、CGLIB動的プロキシ。静的エージェントは、エージェントクラスを指す存在コンパイルであり、逆の動的プロキシは、ランタイムプログラムに動的に生成されます。
第二に、帯電防止剤
プログラムが実行される前に、帯電防止剤は、単にポイントは、エージェントとエージェントクラス・カテゴリー間の関係が確認されています。静的エージェントの実装は、一般に、第1の共通インタフェースを定義する、以下のステップを有し、次のように実装されたプロキシクラスのプロキシクラス:
パッケージcom.bsoft.proxy2; / ** *パブリックインターフェイス * / パブリック・ インタフェースIUserDao { 空保存(); 無効検索(); }
プロキシクラス(プロキシターゲットクラス):
パッケージcom.bsoft.proxy2.impl; インポートcom.bsoft.proxy2.IUserDao; / ** *と呼ばれているプロキシプロキシクラスまたは特定のクラス * / パブリック クラス UserDaoImpl 実装IUserDao { @Override 公共 のボイド保存(){ のSystem.out。 println( "シミュレートされたユーザーが保存" ); } @Override 公共 ボイド検索(){ System.out.printlnは( "ユーザークエリアナログ" ); } }
プロキシクラスが続きます
パッケージcom.bsoft.proxy2.impl; インポートcom.bsoft.proxy2.IUserDao; / ** *プロキシクラス * / パブリック クラス UserDaoProxy 実装IUserDao { プライベート UserDaoImpl UD = 新新UserDaoImpl(); @Override 公共 無効保存(){ システム.out.println( "エージェントの動作、オープントランザクション" ); ud.save(); のSystem.out.println( "エージェント、トランザクションを閉じる" ); } @Override 公共 ボイド検索(){ System.out.printlnは(「代理店業務、開いているトランザクション」); ud.find(); のSystem.out.println( "ああエージェント操作は、トランザクションを閉じます" ); } }
プロキシクラスの論理メソッドを追加する前に、または他の処理ロジック方法の添加後に方法の前に、プロキシエージェントオブジェクトクラスのインスタンスによって呼び出され、プロキシクラスは、プロキシクラスでインスタンス化されて保持していることが分かるであろう。
最後に、プロキシクラスのテストメソッドを使用して見てください:
パッケージcom.bsoft.proxy2; インポートcom.bsoft.proxy2.impl.UserDao; インポートcom.bsoft.proxy2.impl.UserDaoProxy; インポートorg.junit.Test; パブリック クラスTest2を{ / ** *直接、プロキシを使用していませんプロキシクラス * / 公共 ボイドTEST1(){ System.out.printlnは( "未使用のプロキシモード------ ----------" ); iUserDao iUserDao = 新しい新しいUserDao(); iUserDao .SAVE(); のSystem.out.println( "----------------" ); iUserDao.find(); } / ** *静的剤 *帯電防止剤及び帯電防止剤を使用することなく、エージェントの使用の後に見いだされることができるような動作を実現するために、エージェントの実行前または方法の後に他のコードに追加することができ、許可ログ * / @Test 公共 ボイドTEST2(){ システム.out.println( "静的プロキシモード------- --------" ); IUserDao iUserDao = 新しい新しいUserDaoProxy(); iUserDao.save(); のSystem.out.println(「 - ------------------ " ); iUserDao.find(); } }
Test1のテストの実行には、次の結果が返されました:
------ ----------プロキシモードは使用しない
ユーザーを保存するためにシミュレーションを
----------------
ユーザークエリをシミュレート
Test2をテストの実行には、次の結果が返されました:
スタティックモード-------- -------プロキシ エージェントの操作、オープン総務 アナログは、ユーザーの保存 、エージェントをトランザクションを閉じ ------------------- - 代理店業務、オープン総務 ユーザー照会するアナログ エージェントの操作ああ、シャット総務を
比較した後、帯電防止剤の使用や帯電防止剤を使用しない、プロキシは見つけることができ、このような操作や許可ログを達成するために、プロキシメソッドの実行前または後に他のコードに追加することができます。
プロキシメソッドは、それがコードの保守のコストを増大させる、各プロキシメソッドのために必要である場合は、いくつかの帯電防止剤、たくさんあります。そこのコードのメンテナンスを削減する他の方法はありません、それは動的プロキシです。
三、JDKの動的プロキシ
JDKプロキシクラスを生成することができる、動的プロキシモードを提供し、プロキシは、プロキシクラスのインターフェースとクラスは、以下の帯電防止剤とIUserDao UserDaoImplを継承見られます。
パッケージcom.bsoft.proxy3; インポートjava.lang.reflect.InvocationHandler; インポートjava.lang.reflect.Methodオブジェクト; / ** * JDKダイナミックプロキシクラス * / パブリック クラス DynamicProxy 実装のInvocationHandler {の // プロキシインスタンス のプライベートIUserDao iUserDao ; // コンストラクタ パブリックDynamicProxy(iUserDao iUserDao){ この .iUserDao = iUserDaoは; } @Override パブリックオブジェクト呼び出しを(プロキシは、この方法は、この方法は、[]引数オブジェクトオブジェクト)スローのThrowable { オブジェクト結果 = NULLを; のSystem.out.println( "JDK動的プロキシを起動" ); 結果は = Method.invoke(iUserDao、引数); のSystem.out.printlnは( "JDKダイナミックプロキシーエンド" ) のSystem.out.println(「結果== ==「+ 結果); 戻り値の結果; } }
InvocationHandlerがその中に実装されたメソッドを呼び出して、JDKにインターフェースを実装する必要があり、プロキシクラスのメソッドは、他の処理は、次のテストコードを参照して、方法の前または後に行うことができ、反射モードでこのメソッドによって呼び出されます。
パッケージcom.bsoft.proxy3; インポートcom.bsoft.proxy2.impl.UserDaoImpl; インポートjava.lang.reflect.Proxyの、 パブリック クラスTest3は{ / ** * JDKダイナミックプロキシテスト * / パブリック 静的 ボイドメイン(文字列[]引数){ UserDaoImpl userDao = 新しい新しいUserDaoImpl(); DynamicProxy DynamicProxy = 新しい新しいDynamicProxy(userDao); // 最初のクラスローダのプロキシオブジェクトを生成するプロキシクラスであり、第2のインターフェースは、プロキシクラス、第として実装されそれはのInvocationHandlerた実装クラス、従ってプロキシオブジェクトを生成 iUserDao iUserDao =(IUserDao)たとえば、Proxy.newProxyInstance(userDao.getClass()のgetClassLoader()、userDao.getClass()でgetInterfaces()、dynamicProxy。)。 iUserDao.save(); System.out.println( "------------------" ); iUserDao.find(); } }
プロキシクラスuserDaoの方法により試験コードnewProxyInstanceでプロキシクラスのインスタンスを生成し、三つのパラメータ、プロキシクラスのためのクラスローダである第1の必要と、第2のインターフェースは、第三の、プロキシクラスとして実装されていますInvocationHandlerの実装クラスに、このようにプロキシオブジェクトを生成し、プロキシは、オブジェクトのメソッドを呼び出すことによって実行される以下の通りでした:
JDKダイナミックプロキシ起動し 、ユーザー保存するシミュレーション エンドJDKの動的プロキシに 検索結果を ==== ヌル ------------------ プロキシJDKの動的起動 シミュレートユーザーのクエリが 終了し、JDKの動的プロキシに 検索結果を === = nullを
上記プロキシプロキシクラスから分かるように、動的クラスnewProxyInstance法によって生成され、オブジェクトは「呼び出しインスタンスメソッド」を用いて生成されたメソッド呼び出しを意味し、プロキシクラス関係は、コード行の実装にのみプロキシクラスでありますときので、動的プロキシになってきて、生成されます。
JDKダイナミックもプロキシ欠点、すなわち、プロキシクラスを実装しなければならないインターフェイスは、このようなインターフェイスは、第2のパラメータnewProxyInstance法から知ら(JDKダイナミックプロキシなしに使用することができない、プロキシクラスインターフェースを実装することが通過しなければなりません)、あなたはCGLIB動的プロキシを使用する必要があります。
四、CGLIB動的プロキシ
CGLIB動的プロキシは、インターフェイスを実装する必要があり、それはそのサブクラスを使用して、継承されるプロキシクラスを使用するプロキシクラスである必要はない動的プロキシクラスライブラリのサードパーティ製の実装であり、不足エージェントクラスにアップしているインターフェイスはありません
CGLIBを使用するにはサードパーティのライブラリの導入でなければなりません。ASM-3.2.jar、CGLIB-2.22.jar。
CGLIBプロキシを使用するには、プロキシクラスはそのMethodInterceptorのインタフェースを実装する必要があります。
パッケージcom.bsoft.proxy4。 輸入net.sf.cglib.proxy.MethodInterceptor。 輸入net.sf.cglib.proxy.MethodProxy; 輸入java.lang.reflect.Methodオブジェクト。 / ** * CGLIB动态代理 * / パブリック クラス MyMethodInterceptorは実装MethodInterceptorの{ @Override パブリックオブジェクトインターセプト(オブジェクトobj、メソッドのメソッド、オブジェクト[]引数、MethodProxyプロキシ)はスローのThrowable { するSystem.out.println( "开始CGLIB动态代理"を); 対象物体 = proxy.invokeSuper(OBJ、引数)。 System.out.println( "结束CGLIB动态代理"); 戻り値のオブジェクト。 } }
プロキシクラス:
パッケージcom.bsoft.proxy4; パブリック クラスTeacherDao { 公共 空保存(){ System.out.printlnは( "教師のアナログ保存" ); } 公共 ボイド検索(){ System.out.printlnは( "クエリ教師アナログ" ); } }
次のようにどのテストコードは次のようになります。
パッケージcom.bsoft.proxy4。 輸入net.sf.cglib.proxy.Enhancer。 パブリック クラスTEST4 { / ** * CGLIB动态代理测试 * @param 引数 * / パブリック 静的 ボイドメイン(文字列[]引数){ エンハンサーエンハンサー = 新しいエンハンサー()。 enhancer.setSuperclass(TeacherDao。クラス); enhancer.setCallback(新しいMyMethodInterceptor()); // 生成代理类 TeacherDao teacherDao = (TeacherDao)enhancer.create(); (teacherDao.saveを)。 System.out.printlnは("----------------" ); teacherDao.find(); } }
エンハンサーは、プロキシクラスを生成するために使用見ることができ、親クラスであるプロキシクラスを設定する必要があり、提供されるコールバックメソッド(ここで、継承、生成されたサブクラスを使用するように見ることができます)。
スタートCGLIB動的プロキシ 教師保存アナログは CGLIB動的プロキシを終了 ---------------- CGLIB動的プロキシ開始 シミュレーションクエリの先生を CGLIB動的プロキシを終了
時間を設定することで、あなたは匿名内部クラスを使用することができますコールバックenhancer.setCallback MethodInterceptorのインスタンスを、渡す必要があります。
V.の概要
要約を作るために帯電防止剤、JDKの動的プロキシ、CGLIB動的プロキシは、静的なエージェントのメンテナンスコストが高い、プロキシクラスエージェントクラスを作成する必要があり、同じインタフェースを実装する必要があります。JDKダイナミックプロキシモードとCGLIB動的プロキシ差がJDK動的プロキシ・インターフェース・エージェントクラスに実装する必要があるが、CGLIBは、プロキシクラスのサブクラスで生成された最終的なクラスが継承することができないので、エージェントクラスは、最終的なことができないことが求められます。