1 动态代理

    动态代理设计模式的原理:使用一个代理对象将原对象(目标对象)包装起来,然后利用该代理对象取代原对象。    任何对原对象的调用都要经过代理。代理对象决定是否以及何时将方法调用转到原对象上。

2 动态代理用那些?

        1 基于接口的动态代理 : 如 JDk 提供的代理        2 基于继承的动态代理 : 如第三方包 Cglib,javassist 动态代理

这里我们进行演示JDK 自身提供的代理:
jdk动态代理需要实现两个成员:一个是Proxy代理类,一个是InvocationHandler接口

    1  JDK动态代理类        Proxy : 所有动态代理对象的父类,专门用于生成代理类对象或者代理对象             public static Object newProxyInstance(ClassLoader loader,             Class<?>[] interfaces,             InvocationHandler h)    2 接口        InvocationHandler   完成动态代理的整个过程(动态代理类的调用处理程序都必须实现InvocationHandler接口)         proxy : 动态代理对象         method : 正在被调用的方法对象         args   : 正在被调用的方法参数         public Object invoke(Object proxy, Method method, Object[] args)         throws Throwable;

接口和实现方法

public interface Arithmetic {    public int add(int a,int b );    public int mul(int a,int b );}public class ArithmeticImpl implements Arithmetic {    @Override    public int add(int a, int b) {        return a + b;    }    @Override    public int mul(int a, int b) {        return a * b;    }}

代理对象

/**    生成代理对象 **/public class ProxyObject  {    //目标对象    private Object target;    public ProxyObject(Object target) {        this.target = target;    }    //获取代理对象    public Object getProxy(){        //代理对象        Object proxy = null;          /*                ClassLoader loader : 目标对象的类加载器                Class<?>[] interfaces : 接口们,目标对象提供的所有接口对象                InvocationHandler h :  代理类的调用处理对象需要实现的接口         */        ClassLoader loader = target.getClass().getClassLoader();        Class<?>[] interfaces = target.getClass().getInterfaces();        InvocationHandler h = new MyInvocationHandler(target);        //这里创建代理对象,使得代理对象和目标对象拥有相同的方法行为,h是代理对象调用处理执行的方法。        proxy = Proxy.newProxyInstance(loader,interfaces,h);        return proxy;    }}class MyInvocationHandler implements InvocationHandler{    private Object target;    public MyInvocationHandler(Object target) {        this.target = target;    }    //代理对象调用代理方法,会回来调用 invoke 方法    // proxy 代理对象 ,一般不会使用    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println(" 动态代理对象 : " + proxy.getClass());        System.out.println(" 正在被调用的方法方法对象 : " + method);        System.out.println(" 正在被调用的方法方法名 : " + method.getName());        System.out.println(" 正在被调用的方法参数 : " + Arrays.asList(args));        System.out.println("执行方法前 ");        //实际上是内部在这儿使用目标对象执行目标方法。        Object result = method.invoke(target,args); //目标对象,调用目标方法 相当于 ArithmeticImpl调用自己的方法        System.out.println("执行方法后 result = " +  result);        return result;    } }

测试

    public static void main(String[] args) {        //目标对象        Arithmetic target = new ArithmeticImpl();        //获取代理对象        Object object =  new ProxyObject(target).getProxy();        Arithmetic proxyObject = (Arithmetic) object;        proxyObject.add(1,2);    }

结果

 动态代理对象 : class com.sun.proxy.$Proxy0 正在被调用的方法方法对象 : public abstract int com.example.demo.service.Arithmetic.add(int,int) 正在被调用的方法方法名 : add 正在被调用的方法参数 : [1, 2]执行方法前 执行方法后 result = 3

$Proxy0 就是我们的动态代理对象

可以在main方法中添加一行代码将代理的对象字节码打印出来!

   byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class<?>[]{Arithmetic.class});        try {            String pathDir = "E:\\";            String path = "\\$Proxy0.class";            File f = new File(pathDir);            if (!f.exists()) {                f.mkdir();            }            path = f.getAbsolutePath() + path;            f = new File(path);            if (f.exists()) {                f.delete();            }            f.createNewFile();            try (FileOutputStream fos = new FileOutputStream(path)) {                fos.write(bytes);            } catch (Exception e) {                e.printStackTrace();            }                } catch (IOException e) {            e.printStackTrace();        }

反编译后 $Proxy0 代码

import com.example.demo.service.Arithmetic;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy0  extends Proxy  implements Arithmetic{  private static Method m1;  private static Method m2;  private static Method m4;  private static Method m3;  private static Method m0;    public $Proxy0(InvocationHandler paramInvocationHandler)    throws   {  //调用父类Proxy  设置 InvocationHandler  代理对象处理器,设置调用代理方法 h     super(paramInvocationHandler);  }    public final boolean equals(Object paramObject)    throws   {    try    {    //判断需要代理的方法      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }    public final String toString()    throws   {    try    {      return (String)this.h.invoke(this, m2, null);    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }    public final int mul(int paramInt1, int paramInt2)    throws   {    try    {        //处理调用 invoke方法, this 当前代理对象       return ((Integer)this.h.invoke(this, m4, new Object[] { Integer.valueOf(paramInt1), Integer.valueOf(paramInt2) })).intValue();    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }    public final int add(int paramInt1, int paramInt2)    throws   {    try    {      return ((Integer)this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt1), Integer.valueOf(paramInt2) })).intValue();    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }    public final int hashCode()    throws   {    try    {      return ((Integer)this.h.invoke(this, m0, null)).intValue();    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }    static  {    try    {        //判断 是否是对象的方法      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);      m4 = Class.forName("com.example.demo.service.Arithmetic").getMethod("mul", new Class[] { Integer.TYPE, Integer.TYPE });      m3 = Class.forName("com.example.demo.service.Arithmetic").getMethod("add", new Class[] { Integer.TYPE, Integer.TYPE });      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);      return;    }    catch (NoSuchMethodException localNoSuchMethodException)    {      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());    }    catch (ClassNotFoundException localClassNotFoundException)    {      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());    }  }}

通过代理对象源码可以看到
初始化 h

  public $Proxy0(InvocationHandler paramInvocationHandler)    throws   {  //调用父类Proxy  设置 InvocationHandler  代理对象处理器,设置调用代理方法 h     super(paramInvocationHandler);  }

底层调用

 return ((Integer)this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt1), 

这行代码实际上是通过invoke 调用当前 原目标方法对象 以及参数,也就是我们写的 MyInvocationHandler 类中 invoke 方法。

关于 InvocationHandler 接口中invocation方法中第一个参数proxy说明。
proxy参数表示的是代理对象,那这个参数有何意义呢, 什么时候去使用呢,为什么这里没有使用这个参数呢。
看了很多博客感觉 描述不清,众说纷纭。
jdk中直接这么描述:

the proxy instance that the method was invoked on

一般常用后面两个参数,第一个是代理对象,一般方法中没有用到!