关于JDK动态代理的一点理解

最开始并没有接触过jdk动态的代理的概念,只是在学习spring AOP时知道AOP底层也是用的JDK的动态代理实现的,对于aop也只是知道怎么用,但具体怎么实现的,一直没去考究过。今天终于在看了一些参考资料后硬逼着自己把jdk的动态代理的来龙去脉理解研究了一番。并记载下来以求加深印象。
对于动态代理可以理解为:在程序运行中,程序把我们对目标对象A的访问转移到对代理对象B的访问,因为代理对象B通过一些手段拿到目标对象的方法。
自己定义了四个类:
![这里写图片描述](https://img-blog.csdn.net/20170523170309135?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWl3dXhpYTIz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

首先得定义一个接口,必须得这样(到后面就知道道理了)
public interface AppleDao {
    void eat();
}

再定义一个实现类

public class AppleDaoImpl  implements AppleDao{
    @Override
    public void eat() {
       System.out.println("i want to eat");
    }
}

再定义一个MyInvocationHandler实现InvocationHandler接口

public class MyInvocationHandler implements InvocationHandler {
    //目标对象
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("----before");
            System.out.println(this);
            Object s= method.invoke(target, args);
            System.out.println("----after");
        return s;
    }

}

在这个类里面我在目标方法调用前后分别打印“—-before”和“—-after”
说了这么多,这么目标对象我们已经知道了就是 AppleDaoImpl ,但是代理对象呢?它在哪里?
通过网上查找发现了有这样的方法,可以在程序运行时拿到在运行时生成的类。


public class ProxyGeneratorUtils {

    public static void writeProxyClassToHardDisk(String path){
           byte[] classFile = ProxyGenerator.
           generateProxyClass("$Proxy12", AppleDaoImpl.class.getInterfaces()); 
           FileOutputStream out = null;  
            try {  
                out = new FileOutputStream(path);  
                out.write(classFile);  
                out.flush();  
            } catch (Exception e) {  
                e.printStackTrace();  
            } finally {  
                try {  
                    out.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }    

    }
}

这样所有的准备工作都已经做完了。写一个main方法来测试下:

AppleDao appleDao=new AppleDaoImpl();
            MyInvocationHandler m=new MyInvocationHandler(appleDao);

            AppleDao proxy=(AppleDao)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                                                  appleDao.getClass().getInterfaces(),
                                                  m);
            proxy.eat();
            ProxyGeneratorUtils.writeProxyClassToHardDisk("d:/$Proxy12.class");

首先控制台会打印:

----before
com.jsm.MyInvocationHandler@66bfa709
i want to eat
----after

然后在d盘中会生成一个文件,我们用反编译工具打开这样一个文件

import com.jsm.AppleDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy12 extends Proxy
  implements AppleDao
{
  private static Method m1;
  private static Method m3;
  private static Method m0;
  private static Method m2;

  public $Proxy12(InvocationHandler paramInvocationHandler)
    throws 
  {
    **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 void eat()
    throws 
  {
    try
    {
      **this.h.invoke(this, m3, null);**
      return;
    }
    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);
    }
  }

  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);
    }
  }

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("com.jsm.AppleDao").getMethod("eat", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

现在我们应该明白一些了,代理类就是 $Proxy12 ,它的构造函数会传入一个InvocationHandler 类型的参数,就是我们之前定义的 MyInvocationHandler。因为proxy类中有一个InvocationHandler h属性。代理类继承了Proxy类,同时也实现了AppleDao接口。在实现的eat方法中this.h.invoke(this, m3, null);通过调用我们自定义的MyInvocationHandler类的invoke方法,从而实现在目标方法调用前和调用后完成我们需要干的事情。
这里再回过头来分析下代理类。它实现了AppleDao 接口,(和目标类实现同样的接口),定义一个InvocationHandler 负责去做具体的事情。我们的业务逻辑就包含在这里面,然后代理类负责调用方法执行,完成预期的任务。
非常期待能和各位志同道合者交流讨论,本人QQ 975907209.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值