Java の 3 つのプロキシ モードとは何ですか?

王林
リリース: 2021-02-03 18:52:13
転載
2511 人が閲覧しました

Java の 3 つのプロキシ モードとは何ですか?

まず、プロキシモードとは何かについて簡単に説明します。

プロキシは、ターゲット オブジェクトにアクセスする別の方法、つまりプロキシ オブジェクトを介してターゲット オブジェクトにアクセスする方法を提供するデザイン パターンです。この利点は、次の実装に基づいてターゲット オブジェクトを強化できることです。ターゲット オブジェクト。追加の機能操作、つまり、ターゲット オブジェクトの機能を拡張します。
ここではプログラミングの考え方が使用されています。他の人が書いたコードやメソッドを自由に変更しないでください。必要がある場合は、メソッド

エージェントの役割を説明するための例を示します: スターを招待したいとします。その場合、スターに直接連絡するのではなく、スターの連絡先に連絡します。同じ目的を達成するためのエージェント。スターはターゲットオブジェクトであり、彼はイベントのプログラムに責任を持つだけでよく、その他の些細なことはエージェント(ブローカー)に解決を任せます。これは、エージェントの考え方の一例です。現実.

図は次のとおりです:

Java の 3 つのプロキシ モードとは何ですか?

##プロキシ モードの重要なポイントは、プロキシ オブジェクトとターゲット オブジェクトです。プロキシ オブジェクトは拡張機能です。

#1.1. 静的プロキシ

静的プロキシを使用する場合は、インターフェイスまたは親クラスを定義する必要があります。プロキシ オブジェクトとプロキシ オブジェクト同じインターフェイスを実装するか、同じ親クラスを継承します。

次に説明する例を示します。

保存アクションをシミュレートし、保存アクションのインターフェイスを定義します: IUserDao.java、次にターゲット オブジェクトこのインターフェースのメソッド UserDao.java を実装します。このとき、静的プロキシメソッドを使用する場合は、プロキシオブジェクト (UserDaoProxy.java) に IUserDao インターフェースも実装します。呼び出すときは、 を呼び出して対象のオブジェクトを呼び出します。

プロキシ オブジェクトとターゲット オブジェクトは同じインターフェイスを実装し、同じメソッドを呼び出してターゲット オブジェクトのメソッドを呼び出す必要があることに注意してください。

コード例:

インターフェイス:IUserDao.java

/**
 * 接口
 */public interface IUserDao {    void save();
}
ログイン後にコピー

ターゲット オブジェクト:UserDao.java

/**
 * 接口实现
 * 目标对象
 */public class UserDao implements IUserDao {    public void save() {
        System.out.println("----已经保存数据!----");
    }
}
ログイン後にコピー

プロキシ オブジェクト:UserDaoProxy.java

/**
 * 代理对象,静态代理
 */public class UserDaoProxy implements IUserDao{    //接收保存目标对象
    private IUserDao target;    public UserDaoProxy(IUserDao target){        this.target=target;
    }    public void save() {
        System.out.println("开始事务...");
        target.save();//执行目标对象的方法
        System.out.println("提交事务...");
    }
}
ログイン後にコピー

(学習ビデオ共有:

Javaビデオチュートリアル

)テストクラス:App.java

/**
 * 测试类
 */public class App {    public static void main(String[] args) {        //目标对象
        UserDao target = new UserDao();        //代理对象,把目标对象传给代理对象,建立代理关系
        UserDaoProxy proxy = new UserDaoProxy(target);

        proxy.save();//执行的是代理的方法
    }
}
ログイン後にコピー

静的エージェントの概要:

1. ターゲットを変更せずに実行できます の機能を前提としています

2. 欠点:

プロキシ オブジェクトはターゲット オブジェクトと同じインターフェイスを実装する必要があるため、多くのプロキシ クラスが存在し、クラスが多すぎます。インターフェイスにメソッドを追加するときは、ターゲット オブジェクトとプロキシ オブジェクトの両方を維持する必要があります。

静的プロキシの欠点を解決するにはどうすればよいですか?その答えは、動的プロキシ メソッドを使用できることです

1.2. ダイナミック プロキシ

ダイナミック プロキシには次の特徴があります:

1. プロキシ オブジェクトはインターフェイスを実装する必要はありません

2. プロキシ オブジェクトの生成は API を使用します。メモリ内にプロキシ オブジェクトを動的に構築するための JDK の設定 (プロキシ オブジェクトの作成 / ターゲット オブジェクトによって実装されるインターフェイスのタイプを指定する必要があります)
3. 動的プロキシは、JDK プロキシ、インターフェイス プロキシとも呼ばれます

JDK でプロキシ オブジェクトを生成するための API

プロキシ クラスが配置されているパッケージ: java.lang.reflect .Proxy

JDK ではプロキシを実装するために newProxyInstance メソッドを使用するだけで済みますが、このメソッドは完全な書き込みメソッドは次のとおりです:

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
ログイン後にコピー

このメソッドは Proxy クラスの静的メソッドであり、3 つのパラメーターを受け取ることに注意してください:

ClassLoader ローダー: 現在のクラスローダーを使用するターゲットオブジェクト、およびローダーの取得方法は固定されています

Class[] インターフェイス,:ターゲット オブジェクトによって実装されるインターフェイスのタイプ。タイプを確認するにはジェネリックスを使用します

InvocationHandler h: イベント処理、対象オブジェクトのメソッドを実行すると、イベントプロセッサのメソッドがトリガーされ、現在実行されている対象オブジェクトのメソッドがパラメータとして使用されます。

を渡します。

コード例:

インターフェースクラス IUserDao.java とインターフェース実装クラス 対象オブジェクト UserDao はそのまま同一です これをベースにプロキシファクトリクラス(ProxyFactory.java)を追加し、この中にプロキシクラスを記述しますを配置し、まずテスト クラス (プロキシを使用する必要があるコード) 内のターゲット オブジェクトとプロキシ オブジェクト間の接続を確立してから、プロキシ オブジェクト


で同じ名前のメソッドを使用します。エージェント ファクトリ クラス: ProxyFactory.java

/**
 * 创建动态代理对象
 * 动态代理不需要实现接口,但是需要指定接口类型
 */public class ProxyFactory{    //维护一个目标对象
    private Object target;    public ProxyFactory(Object target){        this.target=target;
    }   //给目标对象生成代理对象
    public Object getProxyInstance(){        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),                new InvocationHandler() {                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("开始事务2");                        //执行目标对象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("提交事务2");                        return returnValue;
                    }
                }
        );
    }

}
ログイン後にコピー

テスト クラス: App.java

/**
 * 测试类
 */public class App {    public static void main(String[] args) {        // 目标对象
        IUserDao target = new UserDao();        // 【原始的类型 class cn.itcast.b_dynamic.UserDao】
        System.out.println(target.getClass());        // 给目标对象,创建代理对象
        IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();        // class $Proxy0   内存中动态生成的代理对象
        System.out.println(proxy.getClass());        // 执行方法   【代理对象】
        proxy.save();
    }
}
ログイン後にコピー

概要:

プロキシ オブジェクトはインターフェイスを実装する必要はありませんが、ターゲット オブジェクトはインターフェイスを実装する必要があります。インターフェイス、そうでない場合は動的プロキシは使用できません


1.3.Cglib プロキシ

上記の静的プロキシ モードと動的プロキシ モードでは、ターゲット オブジェクトがインターフェイスを実装するターゲット オブジェクトである必要がありますが、場合によってはターゲットobject は単なる別個のオブジェクトであり、インターフェイスは実装されていません。この時点では、ターゲット オブジェクトのサブクラスを使用してプロキシを実装できます。このメソッドは Cglib proxy

と呼ばれます。

Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.

JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现.Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.

Cglib子类代理实现方法:
1.需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可.
2.引入功能包后,就可以在内存中动态构建子类
3.代理的类不能为final,否则报错
4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.

代码示例:
目标对象类:UserDao.java

/**
 * 目标对象,没有实现任何接口
 */public class UserDao {    public void save() {
        System.out.println("----已经保存数据!----");
    }
}
ログイン後にコピー

Cglib代理工厂:ProxyFactory.java

/**
 * Cglib子类代理工厂
 * 对UserDao在内存中动态构建一个子类对象
 */public class ProxyFactory implements MethodInterceptor{    //维护目标对象
    private Object target;    public ProxyFactory(Object target) {        this.target = target;
    }    //给目标对象创建一个代理对象
    public Object getProxyInstance(){        //1.工具类
        Enhancer en = new Enhancer();        //2.设置父类
        en.setSuperclass(target.getClass());        //3.设置回调函数
        en.setCallback(this);        //4.创建子类(代理对象)
        return en.create();

    }    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("开始事务...");        //执行目标对象的方法
        Object returnValue = method.invoke(target, args);

        System.out.println("提交事务...");        return returnValue;
    }
}
ログイン後にコピー

测试类:

/**
 * 测试类
 */public class App {    @Test
    public void test(){        //目标对象
        UserDao target = new UserDao();        //代理对象
        UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();        //执行代理对象的方法
        proxy.save();
    }
}
ログイン後にコピー

在Spring的AOP编程中:
如果加入容器的目标对象有实现接口,用JDK代理
如果目标对象没有实现接口,用Cglib代理

相关推荐:java入门教程

以上がJava の 3 つのプロキシ モードとは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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