基本:オブジェクト指向のデザインのアイデア、多型のアイデア、リフレクションのアイデアが必要です。
Java Dynamic Proxyメカニズムの出現により、Java開発者はプロキシクラスを手動で作成することなく、プロキシクラスを動的に取得できます。プロキシクラスは、実行を反映するためにすべてのメソッド呼び出しをデリゲートオブジェクトに派遣する責任があります。派遣実行プロセス中、開発者は必要に応じてデリゲートオブジェクトとその機能を調整することもできます。これは非常に柔軟で柔軟なプロキシフレームワークです。この記事を読むことで、読者はJava Dynamic Proxyメカニズムをより深く理解することができます。この記事では、最初にJava Dynamic Proxyの動作メカニズムと特性に基づいてコードを分析し、動的生成クラスの内部実装を推測します。
エージェントモデルの基本概念と分類
プロキシモード:他のオブジェクトにプロキシを提供して、このオブジェクトへのアクセスを制御します。プロキシオブジェクトは仲介者として機能し、サービスを削除したり、追加のサービスを追加したり、他のサービスを引用したりすることができます。
開発におけるエージェントモードのアプリケーションシナリオ
リモートプロキシ:さまざまな地理的領域のオブジェクトにLAN代表オブジェクトを提供します。
仮想エージェント:必要に応じて多くのリソースを消費するオブジェクトを遅らせ、本当に必要なときに作成します。たとえば、テキストが最初に表示され、次に写真がWebページに表示されます。
保護エージェント:異なるユーザーのアクセス権を制御します。たとえば、顧客登録が成功した後にのみ、操作を追加、削除、変更、チェックすることができます。
スマートリファレンスエージェント:ターゲットエージェントに追加のサービスを提供します。
プロキシモードを実装する方法
継承と集約を使用して動的プロキシを実装する方が良いでしょう!
public interface movable {public void move();} public class car implements moveable {@override public void move(){try {try.sleep(new random(1000)); system.out.println( "... driving ...");} catch(interruptedexception e){// publintac clasprinttacktrace(); car {@override public void move(){//コードを分離し、ビジネスロジックを増やし、long starttime = system.currenttimemillis(); system.out.println( "車が運転し始めます..."); super.move(); long endtime = system.currenttimemillis() "+(終了時間 - スタートタイム)+" MS ");}}プロキシを実装する継承方法
Moveablecar2=newCar2();
car2.move();
集約方法はプロキシを実装します
Carcar=newCar();
Moveablem=newCar3(car);
m.move();
要約します
継承方法は十分に柔軟ではありません。関数が重ねられている場合、プロキシクラスを膨らんでのみ拡張できます。
集約を使用して、エージェントを互いに渡すことができ、プロキシを柔軟に組み合わせることができます。
パブリッククラスCarlogProxyはcar {@Override public void move(){//コードを分離してsystem.out.println( "login start ..."); super.move(); super.move(); super.move(); long endtime = system.system.currenttimillis(); system.out.out.Out.println(); cartimeproxyはmoveable {public cartimeproxy(car car){super(); this.car = car;} private carcar; @override public void move(){//コードを分離し、system.currenttimemillis(); system.out.out.println() endtime = system.currenttimemillis(); system.out.println( "車は... drive ... time:"+(endtime-starttime)+"ms");}}@test:car car = new car(); cartimeproxy ctp = new cartimeproxy(car); carlogproxy = new Carlogproxy(ctp); clp.move(); //インターフェイスCarlogproxy clp1 = new Carlogproxy(car); cartimeproxy ctp1 = new cartimeproxy(clp1); ctp1.move();JDKダイナミックプロキシおよびCGLIBダイナミックプロキシ
JDKダイナミックプロキシ
エージェントの実装
異なるオブジェクトが同じ関数でプロキシクラスを実装したい場合はどうすればよいですか?
この時点で、同じプロキシクラス-------ダイナミックプロキシ:異なるクラス/異なる方法のプロキシの実装に統合することを試みることができます。
一般的なプロセスは次のとおりです。
Java Dynamic Proxyクラスは、java.lang.Refflectパッケージの下にあります。これは、主に次の2つのクラスを含みます。
(1)InterfaceInvocationHandler:このインターフェイスPublicObjectInvoke(objectMethod、object [] args)で定義されているメソッドは1つだけです。
OBJ:通常、プロキシクラスを指します
方法:プロキシメソッドです
ARGSは、この方法のパラメーターの配列です。
この抽象的なメソッドは、プロキシクラスで動的に実装されています。
(2)プロキシ:このクラスは動的プロキシクラスです
statixObjectnewProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh)
グリコシドクラスのインスタンスを返すと、返されたプロキシクラスをプロキシクラスとして使用できます(プロキシクラスでインターフェイスで宣言された方法を使用できます)。
実装例:
@ TimeHandler Public Class TimeHandler InvocationHandler {public TimeHandler(Object Target){super(); this.target = target;} private objectarget;/**パラメーター:*プロキシプロキシオブジェクト*メソッドメソッドメソッドメソッドメソッドメソッド* argパラメーター** return値:*オブジェクト返品値* starttime = system.currenttimemillis(); system.out.println( "車が運転し始めます..."); method.invoke(ターゲット); long endtime = system.currenttimemillis(); system.out.println( "車は時間をかけます..."+(endtime-starttime)+"ms"); @プロキシクラスのインターフェイスpublic interface movable {public void move();}@プロキシクラスパブリッククラスの車はmoveable {@override public void move(){try {shood.sleep(new random()。nextint(1000)); system.out.println( "... driving ...");} catch(arturtedexexception e){// todo auto-jenerated catch e.printstacktrace();}}}}@テスト
パブリッククラステスト{ / *** jdkダイナミックプロキシテストクラス* / public static void main(string [] args){car car = new car(); InvocationHandler h = new TimeHandler(car); class <?> cls = car.getClass(); /**ローダークラスローダー*インターフェイスインターフェイスの実装* H InvocationHandler*/ Movable M =(Movable)Proxy.NewProxyInstance(cls.getClassloader()、cls.getInterfaces()、h); M.Move(); }}&&テスト結果
まとめ
DynamicProxyはそのようなクラスです:
実行時に生成されるクラスです。このクラスは、一連のインターフェイスを実装する必要があります。動的プロキシクラスを使用する場合、InvocationHandlerインターフェイスを実装する必要があります。
JDKダイナミックプロキシの一般的な手順
1.インターフェイスInvocationHandlerを実装するクラスを作成します。
2。プロキシクラスとインターフェイスを作成します
3.プロキシの静的方法を呼び出して、プロキシクラスを作成します
newProxyInstance(classloaderloader、class []インターフェイス、rikocationhandlerh)
4.プロキシを介してメソッドを呼び出します
CGLIBダイナミックプロキシの実装
エージェントの実装
@Introducing cglib-node-2.2.jarパッケージ
@cglibproxyインターセプトクラス実装インターフェイスメソッドインターセプト:インターセプトメソッドを書き直します
パブリッククラスCGLIBProxy実装MethodEnterceptor {private Enhancerenhancer = new Enhancer(); public Object getProxy(class CL){//サブクラスenhancer.setsuperclass(cl); enchancer.setcallback(this); return emancer.create************* returce fructed fricte fructed(this);ターゲットメソッド*メソッド*プロキシクラスのプロキシインスタンス**/@オーバーライドパブリックオブジェクトインターセプト(オブジェクトobj、メソッドM、オブジェクト[] args、methodproxy proxy)スロー可能{system.out.println( "login start ..."); // proxyクラスは親クラスを呼び出します。 end ... "); return null;}}@Proxyクラストレイン
パブリッククラストレイン{public void move(){system.out.println( "列車が運転している..."); }}@Testクラス
パブリッククラステスト{ / *** cglibproxyダイナミックプロキシテストクラス* / public static void main(string [] args){cglibproxy proxy = new cglibproxy(); Train t =(Train)Proxy.getProxy(Train.Class); t.move(); }}##テスト結果:
まとめ
cglibproxyを使用して動的プロキシを実装するための一般的な手順
1.インターフェイスMethodEnterceptorを実装するクラスを作成し、インターセプトメソッドをオーバーライドします
2。プロキシクラスを作成します
3.プロキシクラスのカスタムメソッドを呼び出して、プロキシインスタンスを取得します
4.プロキシインスタンスで実行する必要がある方法を呼び出します
比較概要
JDKダイナミックプロキシ
1.インターフェイスを実装するプロキシクラスのみ
2。インターフェイスのないクラスはJDKの動的プロキシを実装できません
CGLIBダイナミックプロキシ
1。クラスのプロキシの実装
2。実行ターゲットクラスにサブクラスを生成し、メソッド傍受テクノロジーを使用して、すべての親クラスメソッド呼び出しを傍受します。
エージェントの生成ステップをシミュレートします
アイデア:
実装関数:プロキシのnewProxyInstanceを介してプロキシオブジェクトを返します
1。ソースコード(動的生成エージェント)を宣言する
2。ソースコード(jdkcompilerapi)をコンパイルして、新しいクラス(プロキシクラス)を生成します
3.このクラスをメモリにロードし、新しいオブジェクト(プロキシオブジェクト)を生成します
4。プロキシオブジェクトを返します
動的プロキシ実装を改善します
最初に、システムコンパイラを取得し、ファイルマネージャーをコンパイラから取得し、ファイルを取得します。その後、コンパイラはコンパイルタスクを実行します。コンパイルを完了したら、クラスファイルをクラスローダーにロードし、コンストラクターメソッドを介してインスタンスを取得し、newInstance()を呼び出してオブジェクトのインスタンスを受信します。
(1)コンパイラjavacompilercompiler = toolprovider.getSystemJavacompiler()を取得します。
(2)ファイルマネージャーStandardJavafileManagerFilemgr = compiler.getStandardFileManager(null、null、null);
(3)ファイルiterableUnits = filemgr.getJavafileObjects(filename)を取得します。
(4)コンパイルタスクcompilationtaskt = compiler.getTask(null、filemgr、null、null、null、null、units);
(5)メモリにロードします
classloadercl = classloader.getSystemClassLoader();
classc = cl.loadclass( "com.imooc.proxy。$ proxy0");
(6)プロキシオブジェクトのコンストラクターを介してインスタンスを構築する
constructorctr = c.getConstructor(infce);
ctr.newinstance(newcar());
--------
上記のように、内部ビジネスロジックはハードコーディングされています。実際の動的プロキシと動的に指定されたビジネスロジックを実装する方法は?
1.トランザクションプロセッサを作成する必要があります。最初に、インターフェイス、つまりInvocationHandlerを作成します。 JDKをシミュレートするために、インターフェイスの名前はJDKトランザクションプロセッサの名前と同じです。また、ビジネス処理のオブジェクトの特定の方法を表すために使用されるInvoke()というメソッドを記述します。したがって、invoke()メソッドのパラメーターとして特定のオブジェクトとオブジェクトのメソッドを渡す必要があります。 Invoke(ObjectObj、MethodMethod)、Java Reflectionのパラメーターとして使用されるメソッド、およびこのパッケージを導入する必要があります。このようにして、InvocationHandlerインターフェイスが完了します。
2。TimerProxyなどのトランザクション処理の実装クラスを作成して、InvocationHandlerインターフェイスを実装して、構造は
- - - - TimerProxyimplementsInvocationHandler { - - - - - - - - - - 、、、、、、、、、、、 - - - 、、、、、、、、、、、、、、、、... - - - - - - - - - 、 - 、、、、、、、、、、、 - 、 - 、、、、、、、、、、、、、、、、、、、、、、...ターゲットオブジェクトを渡す必要があります。パラメーターがない場合は、パラメーターを記述できません。プロキシオブジェクト構築方法を作成し、ターゲットオブジェクトを初期化します。
3。プロキシクラスのnewProxyInstance()メソッドでは、ターゲットクラスインターフェイスをパラメーターとして使用することに加えて、トランザクションプロセッサの呼び出しハンドラーに合格し、作成されたインスタンスオブジェクトのハードコーディング部分を変更し、トランザクションプロセッサメソッドを使用して置き換える必要があります。難易度は、弦のスプライシングにあります。
要約します
私たちのプロジェクトでは、エージェントパターンには独自の実際的な意味があります。たとえば、特定のJARパッケージの下でクラスを呼び出したい場合は、このクラスを呼び出す前に特別なビジネスロジックを追加できます。この方法は、AOP指向のプログラミングとも呼ばれます。 (元の関数を変更せずに追加の機能を追加します。)
上記は、Java Dynamic Proxy(デザインパターン)コードのすべての詳細な説明です。この記事では、誰にとっても役立つことを願っています。興味のある友人は、このサイトの他の関連トピックを引き続き参照できます。欠点がある場合は、それを指摘するためにメッセージを残してください。このサイトへのご支援をありがとうございました!