動的プロキシの 2 つの方法とは何ですか?

青灯夜游
リリース: 2022-01-06 17:32:05
オリジナル
19158 人が閲覧しました

2 つの方法: 1. JDK 動的プロキシ、リフレクション メカニズムを使用してプロキシ インターフェイスを実装する匿名クラスを生成し、特定のメソッドを呼び出す前に InvokeHandler を呼び出します; 2. CGLIB 動的プロキシ、asm オープン ソースを使用します。パッケージ。プロキシ オブジェクト クラスのクラス ファイルがロードされ、そのバイトコードを変更してサブクラスを生成することによって処理されます。

動的プロキシの 2 つの方法とは何ですか?

#このチュートリアルの動作環境: Windows7 システム、Java8 バージョン、DELL G3 コンピューター。

動的プロキシは、リフレクションの非常に重要なアプリケーション シナリオです。動的プロキシは、一部の Java フレームワークでよく使用されます。たとえば、Spring の AOP と Dubbo の SPI インターフェイスは、Java 動的プロキシに基づいて実装されています。

動的プロキシには 2 つの方法があります:

  • JDK 動的プロキシ: リフレクション メカニズムを使用して実装を生成します。プロキシ インターフェイス 匿名クラスの場合は、特定のメソッドを呼び出す前に InvokeHandler を呼び出します。

  • CGLIB ダイナミック プロキシ: ASM (オープン ソース Java バイトコード編集ライブラリ、バイトコード操作) オープン ソース パッケージを使用して、プロキシ オブジェクト クラスのクラス ファイルをロードし、その文字セクション コードを変更します。処理するサブクラスを生成します。

違い: JDK エージェントはインターフェイスを実装するクラスのエージェントのみを生成できますが、CGlib はクラスのエージェントを実装し、指定されたクラスのサブクラスを生成し、それをオーバーライドします。継承されたクラスを通じて実装されるメソッドは、最終的に変更されたクラスをプロキシすることはできません。

CGlib の使用を強制する

<!-- proxy-target-class="false"默认使用JDK动态代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>

<aop-config proxy-target-class="true">
<!-- 切面详细配置 -->
</aop-config>
ログイン後にコピー

具体的なコード例:

/**
 * 目标接口类
 */
public interface UserManager {    
    public void addUser(String id, String password);    
    public void delUser(String id);    
}
ログイン後にコピー
/**
 * 接口实现类
 */
public class UserManagerImpl implements UserManager {    
    
    @Override
    public void addUser(String id, String password) {    
        System.out.println("调用了UserManagerImpl.addUser()方法!");
    }    
    
    @Override
    public void delUser(String id) {    
        System.out.println("调用了UserManagerImpl.delUser()方法!");
    }    
}
ログイン後にコピー
/**
 * JDK动态代理类
 */
public class JDKProxy implements InvocationHandler {    
    
    // 需要代理的目标对象
    private Object targetObject;    
    
    public Object newProxy(Object targetObject) {
        // 将目标对象传入进行代理    
        this.targetObject = targetObject;
        // 返回代理对象 
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
    }    
    
    // invoke方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 进行逻辑处理的函数
        checkPopedom();
        Object ret = null;
        // 调用invoke方法
        ret = method.invoke(targetObject, args);
        return ret;
    }    
    
    private void checkPopedom() {
        // 模拟检查权限   
        System.out.println("检查权限:checkPopedom()!");    
    }    
}
ログイン後にコピー
/**
 * CGlib动态代理类
 */
 public class CGLibProxy implements MethodInterceptor {    
    
    // CGlib需要代理的目标对象
    private Object targetObject;
    
    public Object createProxyObject(Object obj) {
        this.targetObject = obj;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(obj.getClass());
        enhancer.setCallback(this);
        Object proxyObj = enhancer.create();
        return proxyObj;
    }
    
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object obj = null;
        // 过滤方法
        if ("addUser".equals(method.getName())) {
            // 检查权限
            checkPopedom();
        }
        obj = method.invoke(targetObject, args);
        return obj;
    }    
    
    private void checkPopedom() {
        System.out.println("检查权限:checkPopedom()!");
    }
}
ログイン後にコピー
/**
 * 测试类
 */
public class ProxyTest {
    
    public static void main(String[] args) {
        UserManager userManager = (UserManager)new CGLibProxy().createProxyObject(new UserManagerImpl());
        System.out.println("CGLibProxy:");
        userManager.addUser("tom", "root");
        System.out.println("JDKProxy:");
        JDKProxy jdkProxy = new JDKProxy();
        UserManager userManagerJDK = (UserManager)jdkProxy.newProxy(new UserManagerImpl());
        userManagerJDK.addUser("tom", "root");
    }
}
ログイン後にコピー
// 运行结果
CGLibProxy:
检查权限checkPopedom()!
调用了UserManagerImpl.addUser()方法!
JDKProxy:
检查权限checkPopedom()!
掉用了UserManagerImpl.addUser()方法!
ログイン後にコピー

概要:

1. JDK エージェントはリフレクション メカニズム aop の動的プロキシを実装するために、CGLIB プロキシはバイトコード処理フレームワーク asm を使用して、バイトコードを変更してサブクラスを生成します。したがって、jdk 動的プロキシ方式は、プロキシ オブジェクトの作成効率が高くなりますが、実行効率が低くなります。cglib は、作成効率が低く、実行効率が高くなります。

2. JDK 動的プロキシ メカニズムは委任メカニズムです。具体的には、動的実装です。インタフェースクラスの中で、動的に生成された実装クラス内の元の実装クラスのメソッドを呼び出すハンドラを委任する CGLIBは継承機構を利用する 具体的には、プロキシクラスとプロキシクラスは継承関係にあるため、プロキシクラスをプロキシクラスに割り当てることができるプロキシクラスはインターフェースを持っているので、インターフェースにプロキシクラスを割り当てることもできます。

(推奨チュートリアル:

Java 入門チュートリアル)

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

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!