美文网首页
JDK动态代理实践与原理

JDK动态代理实践与原理

作者: 蓝汝丶琪 | 来源:发表于2018-12-26 14:10 被阅读34次

本篇内容

  1. 介绍JDK动态代理的基本概念
  2. 一些JDK动态代理的疑问
  3. JDK动态代理的Demo
  4. JDK动态代理的原理
  5. 心得

主要思路

  • 被代理类:实际代码类,必须实现至少一个接口 (下文中的Man
  • 代理类:实现代理逻辑的代理类,继承Proxy类和实现被代理类同一个接口 (由JDK动态生成)
  • 接口:连接代理类和被代理类的桥梁 (下文中的Person接口

为什么JDK动态代理必须要有接口呢?

因为生成的代理类是实现了InvocationHandler()接口,代理的逻辑都是由这个接口的invoke()方法实现。因此这个实现接口的对象就是由Proxy来存储,所有代理类就必须要继承Proxy,因此要桥接代理类和被代理类就只能用接口了

而为什么一定要继承Proxy
应该是想

  • 制约必须是代理接口
  • 如果是允许继承类,那么字段的继承会浪费很大的内存,而且会存在final无法被重写的风险

Demo


//Person接口
public interface Person {

    public void name();

    public void age();
}

--------------------------------------------------------------------------
//被代理类    实现了Person接口
public class Man implements Person {

    public void name() {
        System.out.println("我的名字是小米");
    }

    public void age() {
        System.out.println("我今年23");
    }

    public void sing() {
        System.out.println("我不会唱歌");
    }
}

--------------------------------------------------------------------------
public class JDK {

    //获取代理类,只是创建了个类来实现重写InvocationHandler.invoke()方法
    static class ManProxy{
        private Man man;

        public ManProxy(Man man) {
            this.man = man;
        }
        
        //创建代理类过程 调用Proxy.newProxyInstance()
        public Person getProxy() {
            return (Person) Proxy.newProxyInstance(man.getClass().getClassLoader(), man.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public String toString() {
                    return "这是InvocationHandler的toString";
                }

                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if (method.getName().equals("name")) {
                        System.out.println("你是在问我的名字吗?");
                        method.invoke(man, args);
                    } else if (method.getName().equals("age")) {
                        System.out.println("你是在问我的岁数吗?");
                        method.invoke(man, args);
                    } else if (method.getName().equals("sing")) {
                        System.out.println("你是在问我会唱歌吗?");
                        method.invoke(man, args);
                    }else if (method.getName().equals("toString")) {
                        System.out.println("你执行的是toString");
                        System.out.println(toString());
                        method.invoke(man, args);
                    }

                    return null;
                }
            });
        }
    }

    public static void main(String[] args) {
        ManProxy manProxy = new ManProxy(new Man());
        Person proxy = manProxy.getProxy();
        proxy.name();
        proxy.age();
        System.out.println(proxy.toString());

    }

}

输出:
你是在问我的名字吗?
我的名字是小米
你是在问我的岁数吗?
我今年23
你执行的是toString
这是InvocationHandler的toString
null    //这个输出是main方法里面的调用代理类Proxy0中的toString()方法


核心方法

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException{}

过程

JDK动态代理原理图.png
  • 首先需要代理的类实现InvocationHandler()接口,并重写invoke()方法
  • 代理类生成从Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)开始
    • ClassLoader类加载器:保证与被代理类是同一个类加载器
    • 被代理类的接口数组
  • 调用getProxyClass0()方法
    • 这里首先会从缓存中查找代理类
    • 如果缓存中没有,就会去创建代理类
  • 创建代理类是通过内部类ProxyClassFactory创建的
    • 通过apply()方法创建类
    • 首先是生成代理类的字节码
    • 然后通过字节码来生成一个类
  • 通过代理类的构造方法来创建一个实例,而且初始化的参数是我们实现了InvocationHandler()接口的对象

动态生成的代理类Proxy0.class 反编译后是这样的


// 省略了部分代码
public final class $Proxy0 extends Proxy
  implements person
{
// person接口的方法
  private static Method m1;
  private static Method m2;

  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }
  
// 这个代理类也重写了person的方法,我们调用m1方法的入口就只此处
  public final void m1(String paramString){
  // 全部都会调用到InvocationHandler方法中的invoke中。
  // invoke方法就是实现我们代理逻辑的方法
     this.h.invoke(this, m1, new Object[] { paramString });
  }

 public final void m2(String paramString){
  // 全部都会调用到InvocationHandler方法中的invoke中。
  // invoke方法就是实现我们代理逻辑的方法
     this.h.invoke(this, m1, new Object[] { paramString });
  }

}

心得

为什么是动态

  • 因为是根据被代理类的接口和类加载器生成的字节码,然后在运行时加载的这个class文件去生成对象

相关文章

  • JDK动态代理实践与原理

    本篇内容 介绍JDK动态代理的基本概念 一些JDK动态代理的疑问 JDK动态代理的Demo JDK动态代理的原理 ...

  • Java动态代理

    参考来源: Java动态代理视频 JDK动态代理实现原理 JDK Dynamic Proxies Building...

  • 代理模式

    1.概念 2.静态代理 3.动态代理 3.1 JDK 动态代理 原理 手工模拟JDK动态代理 3.2cglib动态...

  • JDK和CGLIB动态代理区别

    JDK和CGLIB动态代理区别 一 JDK和CGLIB动态代理原理1、JDK动态代理利用拦截器(拦截器必须实现In...

  • AOP——cglib动态代理源码解析

    上一篇分析了使用JDK动态代理的低层实现原理,这次再来看看cglib实现动态代理的原理。 关于JDK动态代理的实现...

  • 动态代理-jdk代理实现原理

    动态代理-jdk代理实现原理 JDK中提供了一个Proxy类用于实现动态代理,JDK的动态代理是基于接口实现的,被...

  • 设计模式~代理模式

    学习代理模式内容: ★ 静态代理、 ★ 动态代理(JDK动态代理、CGLIB动态代理)、 ★ 拦截器的原理和日志记...

  • Spring aop 深入jdk动态代理(自己写动态代理)

    JDK动态代理原理 实际上jdk的动态代理很简单,最重要的方法就是ProxyGenerator.generateP...

  • 面试系列~动态代理实现与原理

    动态代理有JDK动态代理, CGLIB动态代理, SpringAOP动态代理 一,JDK动态代理  jdk动态代理...

  • java动态代理

    目录: 简介 jdk动态代理 cglib动态代理 jdk动态代理与cglib的区别 应用spring的aop 简介...

网友评论

      本文标题:JDK动态代理实践与原理

      本文链接:https://www.haomeiwen.com/subject/nxjhlqtx.html