前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【设计模式】代理模式 ( 动态代理使用流程 | 创建目标对象 | 创建被代理对象 | 创建调用处理程序 | 动态创建代理对象 | 动态代理调用 )

【设计模式】代理模式 ( 动态代理使用流程 | 创建目标对象 | 创建被代理对象 | 创建调用处理程序 | 动态创建代理对象 | 动态代理调用 )

作者头像
韩曙亮
发布2023-03-29 17:25:33
1.3K0
发布2023-03-29 17:25:33
举报
文章被收录于专栏:韩曙亮的移动开发专栏

文章目录

前言

代理模式结构 : 代理模式中的元素有 客户端 , 主题对象 , 被代理对象 , 代理对象 ;

  • 客户端 持有 主题对象 , 调用其方法 ;
  • 代理对象 和 被代理对象 都是 主题 的子类 ;
  • 代理对象 持有 被代理对象 , 可以调用 被代理对象 的方法 ;
在这里插入图片描述
在这里插入图片描述

代理模式的核心 : 代理对象 与 被代理对象 都实现同一个父类或接口 , 这样在客户端使用时 , 客户端 感觉自己与 被代理对象 沟通 , 但用户实际上与 代理对象 进行沟通 ;

一、静态代理的弊端


静态代理 中 , 代理对象 和 被代理对象 必须实现 主题对象 接口 , 如果 主题对象 接口发生改变 , 则相应的 代理对象 和 被代理对象 都要进行相应修改 ;

二、动态代理的优势


动态代理 解决了 静态代理的上述问题 , 不需要手动创建代理对象 , 由 Java 虚拟机实现 代理对象 , 该代理对象自动实现 主题对象 的接口 ;

动态代理执行时 , 动态地创建了字节码文件 , 生成了代理类 ;

三、动态代理使用流程


动态代理使用流程 :

  • ① 创建目标对象 : 创建 目标对象 接口 ;
  • ② 创建被代理对象 : 创建 被代理对象 , 实现 目标对象 接口 ;
  • ③ 创建调用处理程序 : 创建 InvocationHandler 子类对象 , 内部持有 被代理对象 , 在 invoke 方法中 , 返回 method.invoke(subject, args) ;
  • ④ 动态创建代理对象 : 调用 Proxy.newProxyInstance 创建 代理对象 实例对象 , 由 JVM 自动创建代理对象类 , 然后再创建对应的实例对象 ;
  • ⑤ 动态代理调用 : 调用 代理对象 实例的相关 目标对象 接口 方法 ;

1、目标对象接口

代码语言:javascript
复制
/**
 * 目标接口
 *  代理对象 和 被代理对象 都要实现该接口
 */
public interface Subject {
    void request();
}

2、被代理对象

代码语言:javascript
复制
/**
 * 被代理对象
 */
public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("被代理对象 RealSubject request()");
    }
}

3、调用处理程序

代码语言:javascript
复制
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicInvocationHandler implements InvocationHandler {
    /**
     * 持有的 被代理对象
     */
    private Subject subject;

    public DynamicInvocationHandler(Subject subject) {
        this.subject = subject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 调用真实的 被代理对象 的方法
        //  被代理对象的所有的方法的调用都会传到该方法中进行处理
        Object object = method.invoke(subject, args);
        return object;
    }
}

4、客户端

代码语言:javascript
复制
import java.lang.reflect.Proxy;

public class Client {
    public static void main(String[] args) {
        // 被代理对象
        Subject realSubject = new RealSubject();

        // 创建调用处理程序 , 内部持有被代理对象
        DynamicInvocationHandler dynamicInvocationHandler =
                new DynamicInvocationHandler(realSubject);

        // 生成动态代理类
        Subject subject = (Subject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                dynamicInvocationHandler);

        // 动态代理调用
        subject.request();
    }
}

执行结果 :

在这里插入图片描述
在这里插入图片描述

四、动态生成 代理对象 类 的 字节码 文件数据


动态代理 中的 代理对象对应的 字节码类 是由 Java 虚拟机自动生成的 , 在 java.lang.reflect.Proxy 中 , 调用 ProxyGenerator.generateProxyClass 方法 , 生成了 代理对象 类 , 返回的 byte[] 数据就是字节码类对应的二进制数据 ;

代码语言:javascript
复制
            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);

ProxyGenerator 的源码需要下载 JDK 源码查看 , 在 IntelliJ IDEA 开发环境中无法查看 ;

网上找到了一篇博客 , 对此描述的很清楚 JDK动态代理[4]----ProxyGenerator生成代理类的字节码文件解析 ;

ProxyGenerator 中的 generateProxyClass 方法中 , 主要调用了 generateClassFile 方法 , 按照 Class 字节码的规范 , 按照顺序依次写入 魔数 , 次版本号 , 主版本号 , 常量池 , 访问修饰符 , 类索引 等数据 ;

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-09-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 前言
  • 一、静态代理的弊端
  • 二、动态代理的优势
  • 三、动态代理使用流程
    • 1、目标对象接口
      • 2、被代理对象
        • 3、调用处理程序
          • 4、客户端
          • 四、动态生成 代理对象 类 的 字节码 文件数据
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档