Javaエージェントモデルを学ぶには、1つの記事で十分です。

動的プロキシとは

動的プロキシは、ソースコードを変更せずにメソッドを拡張することです。

静的プロキシでは、開発者がプロ​​キシクラスを手動で記述して、ターゲットクラスの拡張を実現する必要があります

プログラムの実行中に、JVM仮想マシンは動的にプロキシオブジェクトを作成します。プロキシオブジェクトを制御し、そのメソッドを拡張できます。

ダイナミックエージェントの原理

  • 動的プロキシでは、同じインターフェイスを実装するためにプロキシクラスとターゲットクラスが必要です
  • リフレクションに基づく動的プロキシ

ダイナミックエージェンシーで最もソウルフルなステップ

プロキシオブジェクトを介して、リフレクションに基づいてターゲットオブジェクトのメソッドが呼び出されます。

method.invoke(xiaoWang、args);

動的エージェントの構成

プロキシオブジェクト

目標

ダイナミックプロキシの実現

  • ダイナミックエージェントの実現技術

      1. jdk 2. cglib
  • 動的プロキシの実装手順

    • インターフェイスを作成する
    • ターゲットクラスとターゲットオブジェクトを作成する
    • プロキシクラスなしでプロキシオブジェクトを作成します
    • プロキシオブジェクトのメソッドを呼び出すと、プロキシは成功します
  • 動的プロキシの実装

    • プロキシツールの紹介

      static Object newProxyInstance(ClassLoader loader、Class <?> [] interfaces、InvocationHandler h);

      3つのパラメーター

      最初のパラメータローダーターゲットクラス(オブジェクト)のローダー

      xiaoWang.getClass()。getClassLoader()

      2番目のパラメーターは、ターゲットクラス(オブジェクト)のインターフェイス配列をインターフェイスします

      xiaoWang.getClass()。getInterfaces()

      3番目のパラメータh:プロセッサインターフェイス。このパラメータでは、ターゲットメソッドが拡張されています。

      2つの方法

      1つ:匿名の内部クラス

      2:ラムダ式

      動的エージェントはメソッドによってのみ強化されます。

      3番目のパラメーターを実装するときは、invokeメソッドを書き直し、invokeメソッドのターゲットメソッドを拡張する必要があります

      オブジェクトinvoke(オブジェクトプロキシ、メソッドメソッド、Object [] args)

      最初のパラメータは、プロキシツールクラスxiaozheによって生成されたプロキシオブジェクトです。

      2番目のパラメーターメソッドは、リフレクションに基づいて、現在実行されているメソッドのオブジェクトです

      3番目のパラメータargs現在の実行メソッドのパラメータ配列

@Test
public void versi() throws Exception {
    
    
    // 1.创建目标对象
    XiaoWang xiaoWang = new XiaoWang();
    // 2.通过Proxy工具类生产代理类和创建代理对象
    DancerInterface xiaozhe = (DancerInterface) Proxy.newProxyInstance(xiaoWang.getClass().getClassLoader(), xiaoWang.getClass().getInterfaces(), new InvocationHandler() {
    
    
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
            // 当前执行的方法名
            // System.out.println(method.getName());
            // 当前执行方法的参数
            // System.out.println(Arrays.toString(args));
            // 前置增强
            if ("dance".equals(method.getName())) {
    
    
                System.out.println("小哲去工作了");
            }
            // 由代理对象调用目标对象方法
            // method的意思是方法,它是方法对象
            Object result = method.invoke(xiaoWang, args);
 			
            // 后置增强
            if ("dance".equals(method.getName())) {
    
    
                result = "小王回到了家里," + result;
            }
            // 代理对象将结果返回给调用者
            return result;
        }
    });
    // 3.调用方法
    // 目标对象方法,不进行加强,简简单单的就相当于xiaoWang执行了这个方法.
    // String result = xiaoWang.dance("香泽菠菜");
    // 代理对象方法,已增强.
    String result = xiaozhe.dance("香泽菠菜");
    // 看看代理和不代理的区别
    System.out.println(result);
}

最終的には、プロキシオブジェクト実行メソッドである必要があります。リフレクションメカニズムを通じて、プロキシオブジェクト拡張メソッドの内部メソッドは、ターゲットオブジェクトを実行するためのターゲットオブジェクトの元のメソッドのままです。拡張関数は、呼び出しで拡張されます。

プロキシオブジェクトがメソッドを呼び出す場合、3つの内部ステップがあります

1.拡張機能を実行します。

2.ターゲットオブジェクトは、ターゲットオブジェクトメソッドを実行します。

2.拡張機能を実行します。つまり、事前拡張または事後拡張です。

package com.qinghong.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class verwu {
    
    

    public static void main(String[] args) {
    
    

	 //	不使用代理增强
     //	Dancer dancer = new Xiaoqiang();
     //	dancer.dance();

        
     //  静态代理,Xiaozhe是自定义代理类,静态代理,两份代码同时写。
     //  Dancer dancer = new Xiaozhe();
     //  dancer.dance();

    
    //动态代理,动态的创建代理对象,不需要写实体代理类。
       // 创建目标对象
        Dancer dancer = new Xiaoqiang();
       /* 创建代理对象时要注意:
        	1、方法中传的三个参数,代理对象要跟目标对象在类加载器上和接口数组上保持一致,所以传的类加载器和接口数组都是目标对象的。
            2、类加载器,通过类加载器表明代理对象由哪个类加载器加载,要选用跟目标对象一样的类加载器,目标对象的类加载器,别装成猪了,你要装人。
            3、接口数组,通过跟目标对象一模一样的接口数组,你要装别人,你起码得知道别人长啥样,有啥衣服(方法)吧。
            4、处理器接口,增强的业务逻辑。*/
        Dancer xiaozhe = (Dancer)Proxy.newProxyInstance(dancer.getClass().getClassLoader(), dancer.getClass().getInterfaces(), new InvocationHandler() {
    
    
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
                //代理对象中,如何调用目标对象的方法。
                //你们猜,这个method是个啥玩意。
                System.out.println("你去卖烧烤吧");
                //这个方法,包含很多东西啊。
                Object obj = method.invoke(dancer, args);
                System.out.println("我不去");
                
                //方法对象有方法名,代理对象和目标对象是一个方法。
                //本质为让目标对象在这里调用它目标对象的方法.(重点!!!)
                //为什么代理对象执行这个方法就会发生反射?
                /*因为代理对象的这个方法就是在创建代理对象的过程中编写的
                执行这个方法时,自然要跑到上边创建代理对象的invoke方法中
                代理对象内部有一个大大的空间,这个空间里边有目标对象执行它目标对象方法的语句.
                代理对象类内部,动态代理没有物理上的代理类,需要虚拟代理类和目标类实现同一接口,创建代理对象时参数中前两个参数都是反射的基本条件。*/
                return obj;
            }
        });
        //代理对象调用方法
        xiaozhe.dance();
    }
}

プロキシモードの簡単な理解

プロキシオブジェクトは、プロキシオブジェクトを1つのレイヤーにラップし、その内部で追加の作業を行うことです。たとえば、ユーザーはFacebookにアクセスする必要がありますが、通常のネットワークでは直接アクセスできません。ネットワークプロキシは、ユーザーが最初に壁を越えてからFacebookにアクセスするのに役立ちます。これがエージェントの役割です。

リモートプロキシ:中国ではGFWのため、Facebookにアクセスできません。壁を乗り越える方法(プロキシを設定)でアクセスできます。アクセスプロセスは次のとおりです。
(1)ユーザーがHTTP要求をエージェントに送信します。
(2)プロキシはHTTP要求をWebサーバーに送信します。
(3)WebサーバーはHTTP応答をプロキシに送信します。
(4)プロキシはHTTP応答をユーザーに送り返します。

静的と動的の違い

静的プロキシ

プログラマーがプロキシクラスを作成するか、特定のツールがソースコードを自動的に生成してコンパイルします。プロキシクラスの.classファイルは、プログラムが実行される前に存在します。

利点:プロキシにより、クライアントは特定の実装クラスとその方法を知る必要がなくなり、プロキシを知るだけで済みます(デカップリング)

短所:

1.ターゲットクラスはこのメソッドを実装し、プロキシクラスもこのメソッドを実装する必要があり、コードが繰り返されます。

インターフェイスがメソッドを追加する場合、すべての実装クラスはこのメソッドを書き直す必要があり(このインターフェイスは、1つのメソッドに対して1つの実装クラス用にカスタマイズすることはできません。複数の実装クラスが必要です)、すべてのプロキシクラスも次のように書き直す必要があります。この方法では、コードの保守が複雑になります。

2.プロキシオブジェクトは1つのタイプのオブジェクトのみを提供します。複数のタイプのオブジェクトを提供する場合は、各タイプのオブジェクトのプロキシにバインドされます。プログラムの規模がわずかに大きい場合、静的プロキシは機能しません。他のクラスがプロキシを提供する場合は、他のプロキシクラスを再度追加する必要があります。

つまり、静的プロキシクラスは特定のインターフェイス(サービス)のみを提供できます。複数のインターフェイスを提供する場合は、多数のプロキシクラスを作成する必要があります。プロキシクラスを使用してすべてのプロキシ機能を完了する場合は、動的プロキシを使用する必要があります。

動的プロキシ

プログラムの実行時にリフレクションメカニズムによって動的に作成されます。プログラムの実行時に、リフレクションメカニズムを使用して動的プロキシを実現し、さまざまなタイプのオブジェクトをプロキシできます。JAVAプログラムは、OCP(拡張のためにオープン、変更のためにクローズ)の原則(オープンとクローズの原則)に従い、AOP思考の実践です。

利点:

静的プロキシと比較して、動的プロキシの最大の利点は、インターフェイスで宣言されたすべてのメソッドが呼び出しハンドラの集中型メソッド(InvocationHandler.invoke)に転送されることです。このように、インターフェイスメソッドの数が比較的多い場合は、次のことができます。静的プロキシのようにすべてのメソッドを転送する必要のない柔軟な処理。動的プロキシの適用により、クラスの責任がより単一になり、再利用しやすくなります。

動的プロキシと静的プロキシの違い

使用法:静的プロキシは手動でプロキシクラスを作成する必要があります

機能的に:静的プロキシプロキシ1つのタイプ、動的プロキシプロキシ複数タイプ

動的エージェントと静的エージェントの実際のビジネスの違い

小さな例を挙げてください

静的プロキシ。プロキシクラスによって実装されるこのインターフェイスの各メソッドは、ロギングコードを追加する必要があります

動的エージェントの場合、各メソッドにロギングを追加するには、invoke()メソッドにロギングコードを追加するだけで済みます。

·················································· ································

学校を失いましたか?

おすすめ

転載: blog.csdn.net/numbbe/article/details/109271061