デザインパターンダイナミックプロキシ

巴扎黑
リリース: 2017-06-26 09:35:48
オリジナル
1178 人が閲覧しました

1. 動的プロキシの概念

動的プロキシは、JDK 動的プロキシと cglib 動的プロキシの 2 つの方式に分かれています。

jdk ダイナミック プロキシは Java 内のリフレクション メカニズムによって実装されますが、cglib ダイナミック プロキシの最下層は asm の助けを借りて実装されます。

一般に、クラス生成プロセスではリフレクション機構の方が効率的ですが、クラス生成後の関連する実行プロセスではasmの方が効率的です(asmクラス生成プロセスの非効率性は、クラス生成プロセスの非効率性は、クラス生成プロセスで生成されたクラスをキャッシュすることで解決できます) asmの質問)。

もう 1 つ注意しなければならない点があります: jdk 動的プロキシを適用するための前提条件は、ターゲット クラスが統合インターフェイスに基づいている必要があります。上記の前提条件がなければ、jdk 動的プロキシを適用できません。

このことから、jdk 動的プロキシには特定の制限があることがわかります。cglib などのサードパーティ ライブラリによって実装された動的プロキシは、より広く使用されており、効率の点でより多くの利点があります。

2. JDK 動的プロキシ

次のコードは、プロキシ モードを使用して、大文字と小文字を変換する関数を実装します。

インターフェイスと実装クラスを定義します:

ISomeService インターフェイス:

package com.ietree.basicskill.designpattern.dynamicproxy.jdk;/**
 * 接口类
 * 
 * @author Root */public interface ISomeService {
    
    String doFirst();    void doSecond();
}
ログイン後にコピー

SomeServiceImpl 実装クラス:

package com.ietree.basicskill.designpattern.dynamicproxy.jdk;/**
 * 实现类
 * 
 * @author Root */public class SomeServiceImpl implements ISomeService {

    @Overridepublic String doFirst() {
        System.out.println("执行doFirst()...");
        String result = "abcde";return result;
    }

    @Overridepublic void doSecond() {
        System.out.println("执行doSecond()...");
    }

}
ログイン後にコピー

JDK 動的プロキシ クラス:

package com.ietree.basicskill.designpattern.dynamicproxy.jdk;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class Main {public static void main(String[] args) {final ISomeService target = new SomeServiceImpl();        // 使用JDK的Proxy动态代理,要求目标类和代理类必须实现相同的接口,因为其底层的执行原理与静态代理的相同ISomeService service = (ISomeService) Proxy.newProxyInstance(// 目标类的类加载器                target.getClass().getClassLoader(),// 目标类所实现的所有接口                target.getClass().getInterfaces(), new InvocationHandler() {// proxy:代理对象// method:目标方法// args:目标方法的参数列表                    @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 调用目标方法Object result = method.invoke(target, args);if (result != null) {
                            result = ((String) result).toUpperCase();
                        }return result;
                    }
                });
        String result = service.doFirst();
        System.out.println(result);

        service.doSecond();
    }
}
ログイン後にコピー

3. cglib 動的プロキシ

Cglib は優れた動的プロキシですプロキシ フレームワークの最下位層は ASM を使用してメモリ内にプロキシ クラスのサブクラスを動的に生成します。CGLIB を使用すると、プロキシ クラスがインターフェイスを実装していない場合でも、動的プロキシ機能を実装できます。 CGLIB はシンプルで使いやすく、JDK の Proxy 動的プロキシよりもはるかに高速に実行されます。

CGLIB のコア クラス:
net.sf.cglib.proxy.Enhancer – 主要な拡張クラス
net.sf.cglib。 MethodInterceptor – メイン メソッド インターセプト クラス。これは Callback インターフェイスのサブインターフェイスであり、ユーザーが実装する必要があります。 net.sf.cglib.proxy.MethodProxy – JDK の java.lang.reflect.Method のプロキシ クラス。
Object o = methodProxy.invokeSuper(proxy, args);//最初のパラメータはプロキシ オブジェクトですが、無限ループの問題は発生しません。

net.sf.cglib.proxy.MethodInterceptor インターフェイスは、メソッド呼び出しのインターセプトを実装するためにプロキシベースの AOP によってよく使用されるコールバック タイプです。このインターフェイスは 1 つのメソッドのみを定義します
public Object intercept(Object object, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;

最初のパラメータはプロキシ オブジェクト、2 番目と 2 番目のパラメータは3 つのパラメータは、インターセプト メソッドとメソッドのパラメータです。元のメソッドは、java.lang.reflect.Method オブジェクトまたは net.sf.cglib.proxy.MethodProxy オブジェクトを使用した通常のリフレクションを通じて呼び出すことができます。 net.sf.cglib.proxy.MethodProxy の方が高速であるため、通常は net.sf.cglib.proxy.MethodProxy が推奨されます。

次のプログラムは大文字小文字変換関数を実装します:

実装クラス SomeService:

package com.ietree.basicskill.designpattern.dynamicproxy.cglib;/**
 * 实现类
 * 
 * @author Root */public class SomeService {public String doFirst() {
        System.out.println("执行doFirst()...");
        String result = "abcde";return result;
    }public void doSecond() {
        System.out.println("执行doSecond()...");
    }

}
ログイン後にコピー
プロキシ クラス MyCglibFactory:

package com.ietree.basicskill.designpattern.dynamicproxy.cglib;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class MyCglibFactory implements MethodInterceptor {private SomeService target;    public MyCglibFactory() {super();
        target = new SomeService();
    }public SomeService myCglibCreator() {// 创建增强器对象Enhancer enhancer = new Enhancer();// 指定目标类,即父类enhancer.setSuperclass(SomeService.class);// 设置回调接口对象enhancer.setCallback(this);return (SomeService) enhancer.create();
    }

    @Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 调用目标方法Object result = method.invoke(target, args);if (result != null) {
            result = ((String) result).toUpperCase();
        }return result;
    }

}
ログイン後にコピー
テスト:

package com.ietree.basicskill.designpattern.dynamicproxy.cglib;public class Main {public static void main(String[] args) {

        SomeService service = new MyCglibFactory().myCglibCreator();
        
        String result = service.doFirst();
        System.out.println("result = " + result);

        service.doSecond();
    }
}
ログイン後にコピー
実行結果:

りー

以上がデザインパターンダイナミックプロキシの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート