プロキシは本質的に、クライアントとオブジェクトの間の仲介者であり、オブジェクトの非最終的なメソッドを実装します。インターフェイスは、実装が必要なメソッドのリストにすぎず、メソッド呼び出しの代行受信を容易にするため、インターフェイスのプロキシ処理は比較的簡単です。
JavaのProxyクラスは、実行時に指定されたインタフェースのリストを実装するクラスです。プロキシにはInvocationHandlerが関連付けられており、プロキシに対して行われたメソッド呼び出しを代理対象のオブジェクトに委任します。これは、メソッドがオブジェクト自体ではなくそのプロキシで呼び出されるように、間接指示のレベルとして機能します。 InvocationHandler
を実装する必要がある単一の方法があるが、:
public Object invoke(Object proxy, Method method, Object[] args)
を一方、メソッドを呼び出すクライアントは、プロキシおよびその基礎となるオブジェクト表現の違いを見分けることができない、またそれは気にする必要があります。
インターフェイスとは対照的に、クラスを動的にプロキシすることはあまり簡単ではありません。 JavaのProxy
はインターフェイスまたはインターフェイスセットの実行時実装に過ぎませんが、オブジェクトはにはインターフェイスを実装するためにがありません。したがって、プロキシクラスでは、cglibなどのライブラリが動作するバイトコード生成が必要です。 cglibは、JavaのProxy
が実行時にインタフェースを実装できるように、実行時にクラスを拡張できるという意味で、バイトコード(つまりクラスファイル)を動的に生成できるため、プロキシクラスをサポートしています。
多くのプロキシが使用されています。そのような使用の1つは遅延ロードです。レイジーローディングは、オブジェクトグラフ内のオブジェクトが必要なときにのみ読み込まれるようにします。高価でリソースを大量に消費する可能性のある、すべてをすぐにメモリにロードするのではなく、オブジェクトのコレクションを繰り返し処理するなど、アクセスする必要が生じたときにオンザフライで読み込むことができます。コレクション全体を読み込むのではなく、一度に小さなセットを読み込むだけです。これは、プロキシで実現できます。プロキシは遅延ロードされたオブジェクトを表します。データベースからロードされる可能性のあるオブジェクト自体は、プロキシでメソッドが呼び出されるまでロードされません。メソッド呼び出しをインターセプトするプロキシは、オブジェクトをメモリにロードし、メソッド呼び出しをそのメソッドに委譲します。ここ
は、レイジーローディングの実装の例である:
public abstract class LazilyLoadedObject implements InvocationHandler {
private Object target;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (target == null) {
target = loadObject();
}
return method.invoke(target, args);
}
/**
* Loads the proxied object. This might be an expensive operation
* or loading lots of objects could consume a lot of memory, so
* we only load the object when it's needed.
*/
protected abstract Object loadObject();
}
プロキシで呼び出されたメソッドがInvocationHandler
によって処理されるように上記InvocationHandler
プロキシに渡すことになります。ハンドラは、オブジェクトがロードされているかどうかをチェックします。それがなければ、loadObject()
が呼び出されます。これはオブジェクトを取得する何らかのデータベースクエリです。
プロキシはメソッド呼び出しの代行受信を可能にするので非常に強力です。これはAOPの場合です。
私はこの部分(return method.invoke(target、args);)が無限ループになると思います。 –
いいえ、 'InvocationHandler'が' target'のメソッドを呼び出すため、プロキシではなく実際のオブジェクトです。代わりに 'return method.invoke(proxy、args) 'を呼び出すと、無限ループになります。 –
aha。あなたが正しい –