Java 動的プロキシを完全に習得する

WBOY
リリース: 2022-07-26 13:55:47
転載
1645 人が閲覧しました

この記事では、java に関する関連知識を提供します。動的プロキシとは、プログラムの実行時に決定されるプロキシ クラスとターゲット クラスの間の関係を指し、顧客はプロキシ クラスを通じてそれを呼び出します。対象オブジェクトのメソッドは、プログラム実行時に必要に応じて対象クラスのプロキシオブジェクトを動的に作成します。以下では、Java ダイナミック プロキシの原理と実装について事例を交えて詳しく説明しますので、皆様の参考になれば幸いです。

Java 動的プロキシを完全に習得する

推奨学習: 「java ビデオ チュートリアル

「エージェント」という言葉は誰もがよく知っていると思います。簡単に言うと、メーカーに代わって商品を販売し、代理店がメーカーに代わって商品を販売し、顧客が商品を購入する代理店を見つけることです。つまり、 1) 顧客とメーカーの関係は目に見えず、顧客は誰がその背後にいるメーカーなのかを知りません。 2) エージェントは顧客を「位置付け」、必要としている顧客グループにより正確に販売できます。

プロキシ モード

プロキシ モード: このオブジェクトへのアクセスを制御するために他のオブジェクトにプロキシを提供します。つまり、クライアントとターゲット オブジェクトの間の仲介者としてプロキシ オブジェクトを作成します。目的は、ターゲット オブジェクトを保護するか、ターゲット オブジェクトを強化することです。

プロキシ モードを使用すると、通常、次の 2 つの利点があります:

\1) プロキシ クラスの実装を隠すことができます

\ 2) クライアントとプロキシ クラス間の分離を実現でき、プロキシ クラスのコードを変更せずに追加の処理を実行できます。

静的プロキシ

そのため-動的プロキシと呼ばれるソースオブジェクトにアクセスするための明確なプロキシクラスを宣言することで、1つのプロキシは1つの製品のみを提供でき、n個の製品がある場合、n個のプロキシが必要となり、ビジネスの発展に役立ちません。

例: マウスとキーボードという 2 つのインターフェイスがあり、各インターフェイスには実装クラスがあります。

次のコードは、実装クラスは次のとおりです。

public class LogitechMouse implements Mouse{
    @Override
    public void sell() {
        System.out.println("出售罗技鼠标");
    }
}
public class HHKBKeyboard implements Keyboard{
    @Override
    public void sell() {
        System.out.println("出售HHKB键盘");
    }
}
ログイン後にコピー

次に、エージェントが sell() を呼び出す前に販売前の理解を示す文と、呼び出し後の文を出力できるようにする必要があります。

を呼び出した後の -sales サービス。その後、2 つのプロキシ クラス MouseProxyKeyboardProxy

public class MouseProxy implements Mouse {
    private Mouse mouse;

    public MouseProxy(Mouse mouse) {
        this.mouse = mouse;
    }
    @Override
    public void sell() {
        System.out.println("售前了解");
        mouse.sell();
        System.out.println("售后服务");
    }
}
public class KeyboardProxy implements Keyboard{
    private Keyboard keyboard;
    public KeyboardProxy(Keyboard keyboard) {
        this.keyboard = keyboard;
    }
    @Override
    public void sell() {
        System.out.println("售前了解");
        keyboard.sell();
        System.out.println("售后服务");
    }
}
ログイン後にコピー

を記述するだけで済みます。最終的な実行は次のとおりです:

public class Test {
    public static void main(String[] args) {
        Mouse logitechMouse = new LogitechMouse();
        MouseProxy mouseProxy = new MouseProxy(logitechMouse);
        mouseProxy.sell();
        Keyboard hhkbKeyboard = new HHKBKeyboard();
        KeyboardProxy keyboardProxy = new KeyboardProxy(hhkbKeyboard);
        keyboardProxy.sell();
    }
}
ログイン後にコピー

出力:
販売前の理解
販売のためのLogicoolマウス
アフターサービス
販売前の理解
販売のためのHHKBキーボード
アフターセールスサービス

静的エージェントのコードは非常にシンプルで理解しやすいです。このモデルは優れていますが、明らかな欠点もあります。

  • 冗長プロキシ クラスの数。ここにはインターフェイスが 2 つだけあります。n 個のインターフェイスがある場合は、n 個のプロキシを定義する必要があります。
  • インターフェースが変更されると、プロキシ クラスとプロキシ クラスの両方を変更する必要があるため、メンテナンスは容易ではありません。

この時点での問題を解決するには、動的プロキシを使用できます。

動的プロキシ

プログラムの実行時にプロキシ クラスがプロキシを作成する方法は次のとおりです。動的プロキシと呼ばれます。つまり、プロキシ クラスは Java コード内で定義されておらず、実行時に動的に生成されると言われています。

JDK 動的プロキシ

JDK は動的プロキシの作成をサポートしていますバージョン 1.3 以降のプロキシ クラス。主要なコア クラスは 2 つだけです: java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler

引き続き上記の例では、JDK 動的プロキシを使用します。

public class JDKProxy implements InvocationHandler {
    private Object object;
    public JDKProxy(Object object) {
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("售前了解");
        Object invoke = method.invoke(object, args);
        System.out.println("售后服务");
        return invoke;
    }
}
ログイン後にコピー

プロキシ クラス オブジェクトのメソッドを呼び出すと、この「呼び出し」は invoke メソッドに転送されます。

プロキシ クラス オブジェクトはプロキシ パラメータとして渡されます。 ,

パラメーター メソッドは、プロキシ クラスのどのメソッドを具体的に呼び出すかを識別し、

args はこのメソッドのパラメーターです。

このようにして、プロキシ クラス内のメソッドへのすべての呼び出しが呼び出しの呼び出しになるため、統合された処理ロジックを呼び出しメソッドに追加できます (メソッド パラメーターに基づいて異なるプロキシを使用することもできます)クラスメソッドは異なる処理を実行します)。したがって、販売前の理解を中間クラスの invoke メソッドで実装し、次に proxy クラスのメソッドを呼び出して、販売後のサービスを提供することができます。

コードを実行します

public class Test {
    public static void main(String[] args) {
        Mouse logitechMouse = new LogitechMouse();
        JDKProxy jdkProxy = new JDKProxy(logitechMouse);
        Mouse mouse= (Mouse)Proxy.newProxyInstance(jdkProxy.getClass().getClassLoader(), new Class[]{Mouse.class}, jdkProxy);
        mouse.sell();
        HHKBKeyboard hhkbKeyboard = new HHKBKeyboard();
        JDKProxy jdkProxy1 = new JDKProxy(hhkbKeyboard);
        Keyboard keyboard = (Keyboard)Proxy.newProxyInstance(jdkProxy1.getClass().getClassLoader(), new Class[]{Keyboard.class}, jdkProxy1);
        keyboard.sell();
    }
}
ログイン後にコピー

インターフェイスがいくつあっても、必要なプロキシ クラスは 1 つだけであることがわかります。

CGLIB ダイナミック プロキシ

エージェント クラス:

public class CGLIBProcy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    private Object object;
    public CGLIBProcy(Object object) {
        this.object = object;
    }
    public Object getProxy(){
        //设置需要创建子类的类
        enhancer.setSuperclass(object.getClass());
        enhancer.setCallback(this);
        //创建代理对象
        return enhancer.create();
    }
    // o: cglib 动态生成的代理类的实例
    // method:实体类所调用的都被代理的方法的引用
    // objects 参数列表
    // methodProxy:生成的代理类对方法的代理引用
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("售前了解");
        Object invoke = method.invoke(object, objects);
        System.out.println("售后处理");
        return invoke;
    }
}
ログイン後にコピー

実行コード:

public class Test {
    public static void main(String[] args) {
        Mouse logitechMouse = new LogitechMouse();
        CGLIBProcy cglibProcy = new CGLIBProcy(logitechMouse);
        Mouse proxy = (Mouse)cglibProcy.getProxy();
        proxy.sell();
        cglibProcy = new CGLIBProcy(new HHKBKeyboard());
        Keyboard keyboard = (Keyboard)cglibProcy.getProxy();
        keyboard.sell();
    }
}
ログイン後にコピー

JDK プロキシと CGLIB プロキシの違い

  • JDK 動的プロキシはインターフェイスを実装し、CGLIB 動的継承のアイデア
  • JDK 動的プロキシ (ターゲット オブジェクトがインターフェイスを持つ場合) の実行効率は CIGLIB よりも高い
  • オブジェクトにインターフェイス実装がある場合、そうでない場合は、JDK プロキシを選択します。 インターフェイス実装用の CGILB プロキシを選択してください。

推奨学習: "java ビデオ チュートリアル "

以上がJava 動的プロキシを完全に習得するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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