动态代理

核心步骤

1、接口定义
2、实现类定义
3、实现InvocationHandler

核心原理

  1. 接口检查: 确保传入的 Class[] 都是接口,且对当前 ClassLoader 可见。
  2. 查找或生成代理类:
  • 系统(Proxy类)首先会尝试查找是否已经为指定的接口列表(按顺序)生成过代理类。它内部维护了一个缓存(WeakCache)。
  • 如果缓存中没有: 系统会动态生成一个新的代理类(如 Proxy0,Proxy1)的字节码。这个生成的类:
    • extends java.lang.reflect.Proxy (所以所有动态代理对象都是 Proxy 的子类)。
    • implements 你传入的所有接口(如 IService)。
    • 这个类中会为每一个接口方法生成对应的实现。这些实现都长得差不多.这些方法的核心逻辑就是调用父类 Proxy 持有的 InvocationHandler 实例 (h) 的 invoke 方法,并把当前代理对象 (this)、代表该方法的 Method 对象(通过常量池或预加载获得)、以及参数数组传递进去。
  • 加载代理类: 将生成的字节码通过 ClassLoader 加载到 JVM (ART/Dalvik) 中,得到 Class 对象。
  1. 实例化代理对象
    使用反射,通过上一步创建的代理类的构造方法实例化对象。构造方法需传入一个InvocationHandler对象。
  2. 返回代理对象
    将实例化好的代理对象强制转换为你指定的接口类型(如 IService)返回给你。

应用场景

  1. 权限检查代理
  2. 日志输出切面
  3. 性能监控代理

Android 中的注意事项

  1. 性能: 动态代理涉及反射调用 (method.invoke()) 和动态类生成,相比直接调用会带来一定的性能开销。在性能极度敏感的路径(如高频循环)中需谨慎使用。Android 7.0 (API 24) 之前,动态生成代理类使用的是 sun.misc.ProxyGenerator (或类似私有API),性能相对较差。Android 7.0 及以后,ART 使用了更优化的 java.lang.reflect.ProxyBuilder (内部 Native 实现),性能有显著提升。
  2. 接口限制: 只能代理接口方法,不能代理类本身的非接口方法。
  3. 混淆 (ProGuard/R8): 如果你的接口、InvocationHandler 或目标对象会被混淆,需要确保它们在混淆规则中保留(使用 -keep 规则),否则运行时动态代理会因找不到类或方法而崩溃。
  4. InvocationHandler 中的耗时操作: 在 invoke 方法中执行的逻辑,尤其是委托调用 (method.invoke()),会阻塞调用者线程。如果这里有网络请求等耗时操作,必须在后台线程执行,否则会阻塞 UI 线程导致 ANR。
  5. 调试: 生成的代理类名字如 $Proxy0,在调试时看起来可能不太直观。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容