代理模式-JDK动态代理

Spring框架里核心是IOC和AOP。其作用就是“简化开发”。
AOP面向切面编程,其核心就是“解耦”。

Spring中哪些地方使用了AOP?

1.日志管理
2.事务管理
3.权限认证
4.Lazy Loading懒加载
5.Context Process上下文处理
6.Error Handler 错误跟踪(异常捕获机制)
7.缓存处理

为了理解AOP,先来了解很重要的设计模式:代理模式
代理模式目前有jdk动态代理,cglib动态代理。

代理模式的必要条件

简单来说,满足以下三个条件即可:
1.执行者和被代理人;
2.对于被代理人来说,这件事情一定要做,但是被代理人不想自己去做,需要请人代做
3.需要获取被代理人的个人信息

在日常生活中哪些场景使用了代理模式?
媒婆,租房中介,黄牛,经纪人

带着解决问题的三部曲来窥探动态代理
1.是什么
2.为什么
3.怎么做

下面以相亲(媒婆,小明)为例,写代码之前先来简单分析一下:
1.执行者和被代理人——>媒婆和小明
2.对于被代理人来说,这件事情一定要做,但是被代理人不想自己去做,需要请人代做——>小明需要找女朋友,但苦于没有资源,于是找媒婆牵线搭桥
3.需要获取被代理人的个人信息——>小明,男,28岁

jdk动态代理

首先我们定义了一个Person类型的接口,为其声明一个方法

package test.fn.proxy.eg3;

public interface Person {
    //寻找真爱
    void findLove();
}

接着,定义了一个类来实现这个接口,这个类就是我们的真实对象,XiaoMing类:

package test.fn.proxy.eg3;

public class XiaoMing implements Person{

    @Override
    public void findLove() {
        System.out.println("寻找白富美!!!");
    }

}

下一步,我们就要定义一个动态代理类了,每一个动态代理类都必须要实现 InvocationHandler 这个接口,因此我们这个动态代理类也不例外

package test.fn.proxy.eg3;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Meipo implements InvocationHandler{

    //需要代理的真实对象
    private Person target;

    //我们要代理哪个真实对象,就将该对象传进去
    public Object getInstance(Person target){
        this.target = target;
        Class clazz = target.getClass();
        /*
         * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
         * 第一个参数 clazz.getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
         * 第二个参数clazz.getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
         * 第三个参数this, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
         */
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //在代理真实对象前我们可以添加一些自己的操作
        System.out.println("我是媒婆");
        System.out.println("开始海选...");
        //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        method.invoke(this.target, args);
        //在代理真实对象后我们也可以添加一些自己的操作
        System.out.println("结束海选...");
        return null;
    }

}

最后,来看看我们的Client类:

package test.fn.proxy.eg3;

public class Test {
    public static void main(String[] args) {
        Person person = (Person) new Meipo().getInstance(new XiaoMing());
        System.out.println("代理对象:" + person.getClass().getName());
        person.findLove();
    }
}

我们先来看看控制台的输出:

代理对象:com.sun.proxy.$Proxy0
我是媒婆
开始海选...
寻找白富美!!!
结束海选...

到这里,jdk动态代理的代码完成了,有没有疑惑,Meipo类的invoke方法如何被调用?在控制台里可以看出代理对象是重新生成的$Proxy0类,$表示JVM内存生成,Proxy表示代理类,数字0表示第一个,生成从0开始算起。具体还是想了解$Proxy0类究竟是个什么,那先生成$Proxy0.class字节码:

package test.fn.proxy.eg3;

import java.io.FileOutputStream;
import java.io.IOException;

import sun.misc.ProxyGenerator;

public class Test {
    public static void main(String[] args) throws IOException {
        Person person = (Person) new Meipo().getInstance(new XiaoMing());
        System.out.println("代理对象:" + person.getClass().getName());
        person.findLove();
        /*原理:
        1.拿到被代理对象的引用,然后获取它的接口
        2.JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口
        3.把被代理对象的引用也拿到了
        4.重新动态生成一个class字节码
        5.然后编译*/
        //获取字节码
        byte[] data = ProxyGenerator.generateProxyClass("$Porxy0", new Class[]{person.getClass()});
        FileOutputStream os = new FileOutputStream("F:/fn/$Porxy0.class");
        os.write(data);
        os.close();
    }
}

接下来我们去看看生成的$Proxy0.class文件。使用Java Decompiler反编译后内容如下:

import com.sun.proxy..Proxy0;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Porxy0
  extends Proxy
  implements .Proxy0
{
  private static Method m9;
  private static Method m7;
  private static Method m4;
  private static Method m10;
  private static Method m13;
  private static Method m8;
  private static Method m3;
  private static Method m2;
  private static Method m1;
  private static Method m6;
  private static Method m11;
  private static Method m5;
  private static Method m0;
  private static Method m12;

  public $Porxy0(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }

  public final void wait(long paramLong)
    throws InterruptedException
  {
    try
    {
      this.h.invoke(this, m9, new Object[] { Long.valueOf(paramLong) });
      return;
    }
    catch (Error|RuntimeException|InterruptedException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final Object newProxyInstance(ClassLoader paramClassLoader, Class[] paramArrayOfClass, InvocationHandler paramInvocationHandler)
    throws IllegalArgumentException
  {
    try
    {
      return (Object)this.h.invoke(this, m7, new Object[] { paramClassLoader, paramArrayOfClass, paramInvocationHandler });
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final boolean isProxyClass(Class paramClass)
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m4, new Object[] { paramClass })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void wait()
    throws InterruptedException
  {
    try
    {
      this.h.invoke(this, m10, null);
      return;
    }
    catch (Error|RuntimeException|InterruptedException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void notifyAll()
  {
    try
    {
      this.h.invoke(this, m13, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void wait(long paramLong, int paramInt)
    throws InterruptedException
  {
    try
    {
      this.h.invoke(this, m8, new Object[] { Long.valueOf(paramLong), Integer.valueOf(paramInt) });
      return;
    }
    catch (Error|RuntimeException|InterruptedException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void findLove()
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String toString()
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final boolean equals(Object paramObject)
  {
    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 Class getProxyClass(ClassLoader paramClassLoader, Class[] paramArrayOfClass)
    throws IllegalArgumentException
  {
    try
    {
      return (Class)this.h.invoke(this, m6, new Object[] { paramClassLoader, paramArrayOfClass });
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final Class getClass()
  {
    try
    {
      return (Class)this.h.invoke(this, m11, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final InvocationHandler getInvocationHandler(Object paramObject)
    throws IllegalArgumentException
  {
    try
    {
      return (InvocationHandler)this.h.invoke(this, m5, new Object[] { paramObject });
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final int hashCode()
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void notify()
  {
    try
    {
      this.h.invoke(this, m12, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  static
  {
    try
    {
      m9 = Class.forName("com.sun.proxy.$Proxy0").getMethod("wait", new Class[] { Long.TYPE });
      m7 = Class.forName("com.sun.proxy.$Proxy0").getMethod("newProxyInstance", new Class[] { Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;"), Class.forName("java.lang.reflect.InvocationHandler") });
      m4 = Class.forName("com.sun.proxy.$Proxy0").getMethod("isProxyClass", new Class[] { Class.forName("java.lang.Class") });
      m10 = Class.forName("com.sun.proxy.$Proxy0").getMethod("wait", new Class[0]);
      m13 = Class.forName("com.sun.proxy.$Proxy0").getMethod("notifyAll", new Class[0]);
      m8 = Class.forName("com.sun.proxy.$Proxy0").getMethod("wait", new Class[] { Long.TYPE, Integer.TYPE });
      m3 = Class.forName("com.sun.proxy.$Proxy0").getMethod("findLove", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m6 = Class.forName("com.sun.proxy.$Proxy0").getMethod("getProxyClass", new Class[] { Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;") });
      m11 = Class.forName("com.sun.proxy.$Proxy0").getMethod("getClass", new Class[0]);
      m5 = Class.forName("com.sun.proxy.$Proxy0").getMethod("getInvocationHandler", new Class[] { Class.forName("java.lang.Object") });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m12 = Class.forName("com.sun.proxy.$Proxy0").getMethod("notify", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

$Proxy0继承的Proxy类部分源码如下:

public class Proxy implements java.io.Serializable {

    private static final long serialVersionUID = -2222568056686623797L;

    /** parameter types of a proxy class constructor */
    private static final Class<?>[] constructorParams =
        { InvocationHandler.class };

    /**
     * a cache of proxy classes
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    /**
     * the invocation handler for this proxy instance.
     * @serial
     */
    protected InvocationHandler h;

    /**
     * Prohibits instantiation.
     */
    private Proxy() {
    }
}

执行findLove()方法的整个流程,如下:

1.执行Test.findLove()方法
2.调用了$Proxy0.findLove()方法,相关代码如下:

public final void findLove()
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
m3 = Class.forName("com.sun.proxy.$Proxy0").getMethod("findLove", new Class[0]);

3.this.h具体指什么,关键代码如下:

this.h.invoke(this, m3, null);

Proxy类源码如下:protected InvocationHandler h;

4.因为$Proxy0继承Proxy,所以这里的h就是InvocationHandler
5.如何调用Meipo的invoke,看看Meipo类的相关代码可以解释,代码如下:

return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);

这里传入this就是Meipo本身,也是InvocationHandler接口的实现类的引用,也解释了通了调用Meipo的invoke方法。
6.最后看看invoke方法:

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //在代理真实对象前我们可以添加一些自己的操作
        System.out.println("我是媒婆");
        System.out.println("开始海选...");
        //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        method.invoke(this.target, args);
        //在代理真实对象后我们也可以添加一些自己的操作
        System.out.println("结束海选...");
        return null;
    }

可能唯一不理解的代码就是method.invoke(this.target, args);
Object proxy ——>代理对象$Proxy0
Method method ——>代理对象findLove()
Object[] args ——> 代理对象findLove()方法入参
这里可以看见,this.target就是真实对象XiaoMing,由于findLove()没有入参,因此args为空,通过反射机制执行了XiaoMing.findLove()方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值