javaのProxy+InvocationHandlerを探します。

5756 ワード

java.lang.reflect.InvocationHandlerは、プロキシの例の呼び出し処理プログラムによって実現されるインターフェースである。各ブローカの例には、関連付けられた呼び出し処理プログラムがある。プロキシのインスタンス上の方法を呼び出すと、方法の呼び出しは、コード化され、関連付けられた処理プログラムを呼び出す方法に転送される。
public Object invoke(Object proxy、Method、Object[]args)throws Throwable処理エージェントの例では、前の方法の呼び出しがあり、処理結果に戻ります。プロキシの一例における方法が呼び出されると、その関連付けられた起動処理プログラムはこの方法で呼び出される。
 proxy:呼び出し方法の代理例 method:エージェントの例で呼び出されたインターフェース方法に対応する方法オブジェクトであり、この方法オブジェクトはインターフェースで宣言される方法であり、プロキシクラスがプロキシインターフェースの親インターフェースを介して継承される方法であってもよい。 args:ブローカの例を含めて、転送されたパラメータ値のオブジェクト配列を呼び出す。インタフェース方法にパラメータがない場合はnull、オリジナルタイプのパラメータは適切なオリジナルパッケージクラスの例でjava.lang.Integerなどである。 リターン値は、プロキシのインスタンスから呼び出される。インターフェース方法によって宣言された戻りのタイプが元のタイプである場合、元のパッケージクラスの例を返します。そうでなければ、その宣言のタイプを返します。   戻り値がnullであり、インターフェースの方法が戻り類似の元のタイプである場合、Null PointerExceptionを抛り出す。   戻り値とインターフェースメソッド宣言の返却タイプが互換性がない場合は、Class CastExceptionをスローします。 throws:ブローカのインスタンスからのメソッド呼び出しの例外。異常タイプはインターフェースメソッドで投げられる任意の異常タイプか、検査を受けていないか、またはエラーです。   検査された異常を一つ投げ出したら、その検査はインターフェースメソッドで宣言された異常なタイプではないと、一つのアングラルdThrowable Exceptionが投げ出します。
java.lang.reflect.Proxy
 動的エージェントクラスおよびインスタンスを作成するためのstatic方法を提供し、これらの方法により、すべての動的エージェントクラスの親クラスを作成する。 いくつかのインターフェースを作成するエージェント: InvocationHandler handler=new MyInvocationHandler(…) Class proxyClass=Proxy.get ProxyClass(Foo.class.get Class Loader); Foo f=(Foo)proxyClass.get Controuctor(InvocationHandler.class).newInstance(handler);  より簡単なもの: Foo f=(Foo)Proxy.newProxyInstance(Foo.class.get Class Loader),new Class[]{Foo.class}  動的エージェントクラス(エージェントクラス)は、このクラスが作成された後に実行されるときに、インターフェースのリストと動作を実行するように指定されるクラスであり、以下のように説明される。 一つのエージェントインターフェースは、エージェントクラスによって実現されるインターフェースである。 1つのエージェントの例は、プロキシクラスのインスタンスオブジェクトである。 各ブローカの例には、InvocationHandlerインターフェースを実現する処理プログラムオブジェクトが関連付けられている。 プロキシクラスは次の属性になります。  すべてのプロキシインターフェースがpublicなら、プロキシはpublic、final、および非abstractのです。  すべてのプロキシインターフェースがnon-publicなら、プロキシはnon-public、finalと非abstractのです。  名称が限定されていないエージェント類は未指定です。クラス名の空間は文字列「$Proxy」から提供されます。プロキシクラスとして残すべきです。  java.lang.reflect.Proxyを受け継ぐ代理類  一つのエージェントクラスは、完全にその指定されたインターフェース上で作成され、同じ順序で  代理クラスがnon-publicインターフェースを実現すると、そのnon-publicインターフェースと同じパッケージに定義されます。そうでなければ、このプロキシ類のカバンも指定されていません。   注意:カバンの閉鎖は、実行時にある特定のカバンから成功的に定義されているプロキシ類(同じクラスクラスのloaderで定義されているクラスと特定の署名の同じパッケージ)を防止できません。
    プロキシクラスは、作成時に指定されたすべてのインターフェースを実現し、getInterfacesを呼び出すと、同じインターフェースリストを含む配列(シーケンスは、その作成時に指定された)を返します。getMethodsメソッドを呼び出すと、これらのインターフェースのすべてのオブジェクトを含む配列に戻ります。    プロキシ(Proxy.get ProxyClassを通して一つのクラスに戻すとProxy.newProxyInstanceを通して対象の関連するクラスに戻ります)を通過すると、Proxy.isProxyClassはtrueに戻ります。そうしないとfalseに戻ります。    プロキシ類の保護ドメイン(java.security.Protection Domain)は、ブートトラック類によってシステムクラスをロードするのと同じです。プロキシ類のコードは信頼できるシステムコードから生成されるので、保護ドメインは通常java.security.AllPermissionに与えられます。    各プロキシクラスには、publicコンストラクタのパラメータがあり、InvocationHandlerインターフェースの実装を実現し、プロキシのインスタンスのための呼び出し処理オブジェクトを設定します。反射APIを使用してpublic constructorにアクセスするのではなく、1つのプロキシ例もProxy.newProxyInstance方法を呼び出すことによって作成することができ、Proxy.get ProxyClass方法を呼び出すと、コンストラクタを呼び出すと、処理プログラムオブジェクトを呼び出すとの組合せのプロキシ例は以下の属性がある。        プロキシインスタンスのproxyが与えられ、そのプロキシクラスFooを介してそのインターフェースを実現すると、次の表式はtrueに戻る。    proxy instance of Foo    また、このタイプの転換(Foo)proxyも成功しました。    各プロキシの例は、関連付けられたアプリケーションオブジェクトを呼び出し、その構成関数によって設定される。    プロキシの例の前のインターフェース方法は、関連する呼び出し処理プログラムオブジェクトにエンコードおよび転送するinvoke方法を呼び出す。    hashCode、equals、toString方法宣言は、java.lang.Objectでエージェントインスタンスで呼び出したときに、関連する呼び出し処理プログラムオブジェクトinvoke方法に符号化され転送され、同じ方法でインターフェース方法の呼び出しとして、Java.lang.Objectを呼び出します。他のプロキシの例のpublic方法は、java.lang.Objectから継承され、プロキシクラスを介して書き換えられないので、これらの方法の呼び出しは、java.lang.Objectの例のように、複数のプロキシインターフェースで方法を繰り返す。        プロキシクラスの2つのor複数のインターフェースが同じ方法名とパラメータを含む場合、プロキシインターフェースの順序は重要である。繰り返した方法がブローカのインスタンスで呼び出された場合、処理プログラムオブジェクトを呼び出す方法オブジェクトは、必ずしもインターフェース参照タイプによって指定されたものではない。このような制限は、生成されたプロキシクラスにおける対応する実装方法が、どのインターフェースを介して呼び出されたかを決定することができないからである。したがって、重要なインターフェース方法の方法オブジェクト(プロキシインターフェースリストに含まれる方法がコール処理プログラムオブジェクトに伝達される)は、1つのプロキシの例における反復方法が呼び出されるとき、参照の種類にかかわらず、どの方法で呼び出されるかにかかわらず、    一つのエージェントインターフェースが、java.lang.Objectと同じ方法名とパラメータ署名を含む場合、方法オブジェクトは、java.lang.Objectをその音響カテゴリとして使用するjava.Objectを含む。言い換えれば、java.lang.Objectにおけるpublic、non-finalの方法は、通常、すべてのエージェントインターフェースの前に、どの方法オブジェクトが呼び出し処理プログラムオブジェクトに伝達されるかを決定する。    なお、繰り返し方法が呼び出された処理プログラムオブジェクトに転送されると、invoke方法は、検査された異常タイプ(すべてのプロキシインターフェースにおける方法のthrowが文から変換可能な異常タイプ)のみを抛り出すことができ、invokeが異常を確認する場合(プロキシインターフェースの方法で定義される任意の例外タイプに変換できない)、未検査の異常を一つ投げます。この制限は、コール方法オブジェクトのget Exception Typesによって、すべての戻り異常タイプがinvokeメソッドに伝達されるというものではないということです。invoke方法で投げられます。
簡単デモ:
public interface Colorable {

    public void value();
    
}

public class RedColor implements Colorable {

    @Override
    public void value() {
        System.out.println("--------------red-------------");
    }

}

public class ColorableProxy implements InvocationHandler {

    private Colorable colorable;
    private Colorable proxy;
    
    public ColorableProxy(Colorable colorable) {
        this.colorable = colorable;
        this.proxy = (Colorable)Proxy.newProxyInstance(Colorable.class.getClassLoader(), new Class<?>[] { Colorable.class }, this);
    }
    
    public Colorable getProxy() {
        return proxy;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        String methodName = method.getName();

        System.out.println("===========starting invoke function:" + methodName + "==========");
        
        Object result = method.invoke(colorable, args);
        
        System.out.println("=========== invoke function:" + methodName + " success==========");
        return result;
    }

}

public class Main {

    public static void main(String[] args) {
        
        Colorable proxy = new ColorableProxy(new RedColor()).getProxy();
        proxy.value();
    }

}