1。概要<BR />エージェントは設計パターンであり、その目的は、特定のオブジェクトへのアクセスを制御するためのプロキシを別のオブジェクトに提供することを目的としています。プロキシクラスは、デリゲートクラスのプリプロセシングメッセージ、メッセージのフィルタリング、メッセージの転送、およびメッセージがデリゲートクラスによって実行された後にその後の処理を実行する責任があります。動作の一貫性を維持するために、プロキシクラスと委任クラスは通常、同じインターフェイスを実装します。
エージェントの作成期間によれば、エージェントクラスは2つのタイプに分けることができます。
静的プロキシ:プログラマは、ソースコードを自動的に生成してコンパイルするためのプロキシクラスまたは特定のツールを作成します。つまり、プロキシクラスの.classファイルは、プログラムが実行される前にすでに存在します。
動的プロキシ:リフレクションメカニズムを使用して、プログラムが実行されているときに動的に作成および生成します。
動的プロキシメカニズムを実装する前に、静的プロキシを簡単に紹介しましょう。
2。StaticProxy <BR />上記のように、プロキシクラスと委任クラスの両方が通常、同じインターフェイスを実装する必要があります。以下は、このインターフェイスを最初に定義するためです。
パブリックインターフェイスサービス{public void add();}デリゲートクラスは、次のように定義されるインターフェイスの実装です。
public class serviceimpl explments service {public void add(){system.out.println( "add user!"); }}Delegateクラスにいくつかのログを追加する場合、プロキシクラスは次のように定義できます。
Public Class ServiceProxyはサービス{プライベートサービスサービス; Public ServiceProxy(サービスサービス){super(); this.service = service; } public void add(){system.out.println( "service start"); service.add(); System.out.println( "Service End"); }}テストクラスを書く:
public class testmain {public static void main(string [] args){service serviceimpl = new ServiceImpl(); Service Proxy = new ServiceProxy(serviceImpl); proxy.add(); }}テストプログラムを実行すると、結果は次のとおりです。
上記のコードから、静的プロキシクラスは特定のインターフェイスのみを提供できることがわかります。複数の種類のオブジェクトを提供する場合は、各オブジェクトをプロキシする必要があります。すべてのプロキシ関数をプロキシクラスを通じて完了できるかどうかを検討するため、動的プロキシの概念を紹介しました。
3.ダイナミックプロキシJavaの動的プロキシには、主に2つのクラス、プロキシとInvocationHandlerが含まれます。
プロキシ:一連のインターフェイスのプロキシクラスとそのオブジェクトを動的に生成するための一連の静的メソッドを提供します。
//方法1:この方法は、指定されたプロキシオブジェクトに関連付けられたコールプロセッサを取得するために使用されます。 Static InvocationHandler getInvocationHandler(オブジェクトプロキシ)//方法2:この方法は、指定されたクラスローダーに関連付けられた動的プロキシクラスのクラスオブジェクトとインターフェイスのセットを取得するために使用されます。 Static Class GetProxyclass(ClassLoader Loader、class []インターフェイス)//方法3:この方法は、指定されたクラスオブジェクトが動的プロキシクラスのStatic Boolean Isproxyclass(クラスCL)であるかどうかを判断するために使用されます。静的オブジェクトnewProxyInstance(classloaderローダー、クラス[]インターフェイス、招きハンドラーh)
InvocationHandler:これは呼び出しプロセッサインターフェイスであり、Invokメソッドをカスタマイズします。これは、通常、Delegateクラスへのプロキシアクセスが実装される動的プロキシクラスオブジェクトのメソッド呼び出しを中央に処理するために使用されます。
//この方法は、動的プロキシクラスのすべてのメソッド呼び出しを中央に処理する責任があります。最初のパラメーターはプロキシクラスのインスタンスであり、2番目のパラメーターは//呼び出されるメソッドオブジェクトです。/3番目のメソッドは呼び出しパラメーターです。コールプロセッサーのプリプロセスまたはデリゲートクラスインスタンスにディスパッチを送信して、実行オブジェクトを送信します(オブジェクトプロキシ、メソッドメソッド、オブジェクト[] args)
Javaの動的プロキシを実装するには、4つの特定の手順があります。
1. [InvocationHandler Interface]を実装して、独自のコールプロセッサを作成します
2。クラスローダーオブジェクトとプロキシクラスのインターフェイスのセットを指定して、動的プロキシクラスを作成します
3.反射メカニズムを介して動的プロキシクラスのコンストラクターを取得します。その唯一のパラメータータイプは、コールプロセッサークラスインターフェイスタイプです
4.コンストラクターを介して動的プロキシクラスインスタンスを作成します。構築中、プロセッサオブジェクトはパラメーターとして呼ばれ、渡されます。
以下は、上記の4つのステップに基づいて、独自の動的プロキシを実装する例です。
インターフェイスとインターフェイスの実装クラス(つまり、デリゲートクラス)は、上記の静的プロキシのコードと同じです。ここでは、InvocationHandlerインターフェイスを実装して、独自のコールプロセッサを作成します。
public class servicehandleは、InvocationHandlerを実装しています{private Object s; public servicehandle(object s){this.s = s; } public Object invoke(Object Proxy、Method Method、Object args)Throws throwable {system.out.println( "service start"); // invokeは、指定されたパラメーターを使用して指定されたオブジェクト上のこのメソッドオブジェクトで表される基礎となる方法を呼び出すことを意味しますresult = method.invoke(s、args); System.out.println( "Service End");返品結果; }}テストクラスを書く:
public class testmain {public static void main(string [] args){service service = new serviceimpl(); InvocationHandler Handler = new ServiceHandle(service); service s =(service)proxy.newproxyinstance(service.getClass()。getClassLoader()、service.getClass()。getInterfaces()、handler); s.add(); }}テストプログラムを実行すると、結果は静的プロキシと同じです。 Proxの静的メソッドNewProxyInstanceがこれらの2つのステップをカプセル化したため、上記のコードには前に述べた手順2と3がないことがわかります。特定の内部実装は次のとおりです。
//プロキシクラスClazz = proxy.getProxyclass(classloader、new class [] {interface.class、...}); //プロキシインターフェイスを含む一連のインターフェイスのプロキシクラスのクラスオブジェクトを動的に作成します。コンストラクターオブジェクトインターフェイスプロキシ=(interface)constructor.newinstance(new object [] {handler})を介した動的プロキシクラスインスタンス。NewProxyInstance関数の内部実装は次のとおりです。
public staticオブジェクトNewProxyInstance(classloaderローダー、クラス<? //クラスローダーの策定に関連するプロキシクラスタイプオブジェクトを取得し、一連のインターフェイス最終クラス<?> [] intfs = interfaces.clone(); //インターフェイスクラスオブジェクトがクラスローダーに表示され、クラスローダーが認識されるインターフェイスクラスオブジェクトがまったく同じかどうかを確認します。 if(sm!= null){checkproxyaccess(reflection.getCallerClass()、Loader、intfs); } //クラスローダーの策定に関連するプロキシクラスタイプオブジェクトを取得し、インターフェイスのセットクラス<? try {if(sm!= null){checknewproxypermission(reflection.getCallerclass()、cl); } //反射を介してコンストラクターオブジェクトを取得し、プロキシクラスインスタンス最終コンストラクター<?> cons = cl.getConstructor(constructorparams)を生成します。最終的なInvocationHandler ih = h; if(!modifier.ispublic(cl.getModifiers())){AccessController.Doprivileded(new PrivileDaction <void>(){public void run(){cons.setaccessible(true); return null;}}); } return cons.newinstance(new object [] {h}); } catch(Illegalaccessexception | InstantiationException e){new internalerror(e.toString()、e); } catch(InvocationTargetException e){Throwable T = E.GetCause(); if(t instanceof runtimeexception){throw(runtimeexception)t; } else {throw new internalError(t.toString()、t); }} catch(nosuchmethodexception e){新しいinternalerror(e.tostring()、e); }} 4.プロキシクラスをシミュレートして実装します
上記の原則の紹介によれば、プロキシクラスを自分でシミュレートして実装できます。
public class proxy {public staticオブジェクトNewProxyInstance(class inface、rikocationhandle H)スロー例外{string rt = "/r/n"; string methodstr = "";方法[] methods = inface.getMethods(); for(Method m:methods){methodstr+= "@override"+rt+"public void"+m.getname()+"+rt+" {"+rt+" try {"+rt+" method = "+inface.getname()+"。class.getMethod(/"+m.getName(/"+"+"; "h.invoke(this、md);"+ rt+ "} catch(Exception e){e.printstacktrace();}"+ rt+ "}"; } string src = "package test;"+ rt+ "import java.lang.refllect.method;"+ rt+ "public class serviceimpl2を実装します"+ inface.getname()+ rt+ "{"+ rt+ "public serviceimpl2(vocutionhandle h)"+ rt+ "+ rt+"+ "+"+ "+" test.invocationhandle h; "+ rt+ methodstr+"} "; string filename = "d:/src/test/serviceimpl2.java"; //コンパイル(src、filename); //メモリにロードしてインスタンスオブジェクトを作成しますm = loadmemory(h); mを返します。 } private static void compile(string src、string filename)throws ioexception {file f = new file(filename); filewriter filewriter = new filewriter(f); filewriter.write(src); filewriter.flush(); filewriter.close(); //このプラットフォームが提供するJavaコンパイラを取得するJavacompiler Compiler = toolprovider.getSystemJavacompiler(); //標準ファイルマネージャーStandardJavafileManager FileManager = compiler.getSandardFileManager(null、null、null)によって実装された新しいインスタンスを取得します。 //指定されたファイルを表すファイルオブジェクトを取得しますiterable units = filemanager.getjavafileobjects(filename); //将来のコンパイルタスクT = compiler.getTask(null、filemanager、null、null、null、units)を作成します。 //このコンパイルタスクを実行するt.call(); filemanager.close(); } private staticオブジェクトLoadMemory(InvocationHandle H)Throws MalformedurLexception、ClassNotFoundException、NosuchMethodexception、InstantiationException、Illegalaccessexception、rikocationTargetException {] url [] url = new URL [] {new URL( "File:/"+"d:/src/"); //クラスとリソースのロードurlclassloader ul = new urlclassloader(urls);クラスc = ul.loadclass( "test.serviceimpl2"); //クラスオブジェクトで表されるクラスの指定されたパブリックコンストラクターを返します。 Constructor Ctr = c.getConstructor(InvocationHandle.class); //このコンストラクターオブジェクトCTRで表されるコンストラクターメソッドを使用して、コンストラクターメソッドの宣言クラスの新しいインスタンスを作成し、指定された初期化パラメーターオブジェクトM = Ctr.NewInstance(h)でインスタンスを初期化します。 mを返します。 }}5。概要1。いわゆる動的プロキシはそのようなクラスです。実行時に生成されるクラスです。それを生成するとき、あなたはそれに一連のインターフェイスを提供し、クラスを変更して、これらのインターフェイスを実装すると主張する必要があります。ただし、それはあなたのためにかなりの作業を行いませんが、インスタンスを生成するときに提供されるパラメーターハンドラー(つまり、InvocationHandlerインターフェイスの実装クラス)に基づいて実際の作業を引き継ぎます。
2。プロキシの設計により、インターフェイスプロキシのみをサポートします。 Javaの継承メカニズムは、Multiple GedがJavaで本質的に実行不可能であるため、動的プロキシクラスがクラスの動的プロキシを実装できないことを運命づけました。
上記はこの記事に関するものです。すべての人の学習に役立つことを願っています。