invocationHandler_handlermapping原理

invocationHandler_handlermapping原理动态代理是很多框架和技术的基础,spring的AOP实现就是基于动态代理实现的。了解动态代理的机制对于理解AOP的底层实现是很有帮助的。      查看doc文档就可以知道,在java.lang.reflect包中有一个叫Proxy的类。下面是doc文档对Proxy类的说明:      “Adynamicproxyclass(simplyreferredtoasa

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

动态代理是很多框架和技术的基础, spring 的AOP实现就是基于动态代理实现的。了解动态代理的机制对于理解AOP的底层实现是很有帮助的。

       查看doc文档就可以知道,在java.lang.reflect包中有一个叫Proxy的类。下面是doc文档对Proxy类的说明:

       “A dynamic proxy class (simply referred to as a proxy class below) is a class that implements a list of interfaces specified at runtime when the class is created, with behavior as described below. A proxy interface is such an interface that is implemented by a proxy class. A proxy instance is an instance of a proxy class. Each proxy instance has an associated invocation handler object, which implements the interface InvocationHandler.”

        Proxy类的设计用到代理模式的设计思想,Proxy类对象实现了代理目标的所有接口,并代替目标对象进行实际的操作。但这种替代不是一种简单的替代,这样没有任何意义,代理的目的是在目标对象方法的基础上作增强,这种增强的本质通常就是对目标对象的方法进行拦截。所以,Proxy应该包括一个方法拦截器,来指示当拦截到方法调用时作何种处理。InvocationHandler就是拦截器的接口。

      InvocationHandler接口也是在java.lang.reflec

     Object invoke(Object proxy, Method method, Object[] args)

     这个接口有三个参数,其中第二和第三个参数都比较好理解,一个是被拦截的方法,一个是该方法的参数列表。关键是第一个参数。按照doc文档的解析,

      proxy – the proxy instance that the method was invoked on

      也就是说,proxy应该是一个代理实例,但为什么要传入这个参数呢?

      带着这个问题,自己编了个小程序作了一点试验。

///

      public interface IAnimal {

           void info();
      }

    public class Dog implements IAnimal

    {

          public void info() {

             System.out.println(“I am a dog!”);
          }
    }

///
import java.lang.reflect.*;

public class ProxyTest {

 public static void main(String[] args) throws InterruptedException {

  final IAnimal animal = new Dog();
  Object proxyObj =Proxy.newProxyInstance(
    animal.getClass().getClassLoader(),
    animal.getClass().getInterfaces(),
    new InvocationHandler()
    {

     public Object invoke(Object proxy, Method method, Object[] args)
     {

      try {

       System.out.println(“被拦截的方法:” + method.getName());
       return method.invoke(animal, args);
      }
      catch (IllegalArgumentException e) {

       // TODO Auto-generated catch block
       e.printStackTrace();
       return null;
      } catch (IllegalAccessException e) {

       // TODO Auto-generated catch block
       e.printStackTrace();
       return null;
      } catch (InvocationTargetException e) {

       // TODO Auto-generated catch block
       e.printStackTrace();
       return null;
      }
     }
    });
  if(proxyObj instanceof IAnimal)
  {

   System.out.println(“the proxyObj is an animal!”);
  }
  else
  {

   System.out.println(“the proxyObj isn’t an animal!”);
  }
 
  if(proxyObj instanceof Dog)
  {

   System.out.println(“the proxyObj is a dog!”);
  }
  else
  {

   System.out.println(“the proxyObj isn’t a dog!”);
  }
 
  IAnimal animalProxy = (IAnimal)proxyObj;
  animalProxy.info();
  animalProxy.hashCode();
  System.out.println(animalProxy.getClass().getName().toString());
 }
}

程序执行的结果如下:

the proxyObj is an animal!
the proxyObj isn’t a dog!
被拦截的方法:info
I am a dog!
被拦截的方法:hashCode
$Proxy0

从结果可以看出以下几点:

1. proxyObj 是一个实现了目标对象接口的对象,而不同于目标对象。也就是说,这种代理机制是面向接口,而不是面向类的。

2. info方法(在接口中)被成功拦截了,hashCode方法也成功被拦截了,但意外的是,getClass方法(继承自Object 类的方法)并没有被拦截!!

3. 应用调试还可以看出Invocation接口中invoke方法的传入的proxy参数确实就是代理对象实例proxyObj

为何getClass()没有被拦截?proxy参数又有何用呢?

先不管,做一个试验看看。既然这个proxy参数就是代理实例对象,它理所当然和proxyObj是一样的,可以调用info等方法。于是我们可以在invoke方法中加上如下一条语句:

((IAnimal)proxy).info();

结果是:

the proxyObj is an animal!
the proxyObj isn’t a dog!
被拦截的方法:info
被拦截的方法:info

…….

被拦截的方法:info
被拦截的方法:info

然后就是栈溢出

结果是很明显的,在invoke方法中调用proxy中的方法会再一次引发invoke方法,这就陷入了死循环,最终结果当然是栈溢出的。

可以在invoke方法中调用proxy.getClass(), 程序可以正常运行。但如果调用hashCode()方法同样会导致栈溢出。

       通过上面的试验,可以得出一些初步结论,invoke 接口中的proxy参数不能用于调用所实现接口的方法。奇怪的是hashCode()和getClass()方法都是从Object中继承下来的方法,为什么一个可以另一个不可以呢?带首疑问到doc文档看一下Object中这两个方法,发现getClass()是定义为final的,而hashCode()不是。难道是这个原因,于是找到一个非final方法,如equals试了一下,真的又会导致栈溢出;找另一个final方法如wait(),试了一下,invoke又不拦截了。final 难道就是关键之处?

      还有一个问题就是proxy有什么用?既然proxy可以调用getClass()方法,我们就可以得到proxy的Class类象,从而可以获得关于proxy代理实例的所有类信息,如方法列表,Annotation等,这就为我们提供的一个分析proxy的有力工具,如通过分析Annotation分析方法的声明式事务需求。我想传入proxy参数应该是这样一个用意吧。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/hli33/archive/2009/05/20/4204387.aspx

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/218951.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 阿基里斯追乌龟的思考,空间,时间,速度非连续

    阿基里斯追乌龟的思考,空间,时间,速度非连续高中的时候才接触和了解,诺阿基里斯追乌龟的悖论,一直萦绕在自己的心头。在上大学的时候,学习了微积分,自己以为自己懂了,但是最近又思考的时候,发现大学里的那种想法还是存在着一些矛盾,自己没有意识到。再度思考,将自己的想法记录下来,如果存在问题,还请多多指教。按照积分将追逐的过程映射为无限级数的和,然后极限求解,但是极限本身就是一个无限接近但是不可到达的过程,因此在我看来…

    2022年6月18日
    31
  • 网页内容变化监控提醒

    网页内容变化监控提醒有很多的人都需要查看网站的变化并且提醒,比如说股票的股市,商品的价格等等。这次案例以实时监控天气温度来简要的说明监控方法,监控的时广州的实时气温,网站会不断的更新当前的气温。首先打开软件网页自动操作通用工具PageOperator,在任务菜单中新建一个刷新操作。点击添加按钮,并把网址输入到对应的地方。点击自动获取,获取网站的编码方案,点击添加,…

    2022年7月17日
    45
  • Socket无限SocketTimeoutException真凶–WLAN助手

    Socket无限SocketTimeoutException真凶–WLAN助手看到标题你可能不知道我说的是什么鬼东西,但是如果你有类似的经历的话,那么恭喜你,也恭喜我自己,终于解决这个问题了。用过小米、华为等手机的都知道,当我们连接上一个不能上网的WIFI时,系统都会友好的给出“此WLAN无法访问互联网,请更换网络/切换为移动数据网络”等类似的提示,今天我就说下本人在这里面遇到的坑。背景:有个Android项目需要连接硬件设备的WIFI,然后通过socket进行通信…

    2022年10月21日
    2
  • Ant笔记(一)Ant下载与安装

    Ant笔记(一)Ant下载与安装此系列参考官方文档http://ant.apache.org/manual/index.htmlAnt是什么ApacheAnt是一个java为基础的构建工具,它跨平台,使用清晰,功能强大。

    2022年7月13日
    16
  • hashmap面试题简书_三年php面试题

    hashmap面试题简书_三年php面试题这篇文章仅限小编个人的理解,小编不是Java方向的,只是对Java有很高的学习兴趣如果有什么不对的地方还望大佬指点HashMap的底层是数组+链表,(很多人应该都知道了)JDK1.7的是数组+链表(1.7只是一个例子,以前的话也是这样后面就以1.7为例子了)首先是一个数组,然后数组的类型是链表元素是头插法JDK1.8的是数组+链表或者数组+红黑树首先是一个数组,然后数组的类型是链表在链表的元素大于8的时候,会变成红黑树在红黑树的元素小于6的时候会变成链表元素进行尾插HaspM.

    2022年8月10日
    6
  • 【转载】句柄和指针的区别

    【转载】句柄和指针的区别

    2021年11月18日
    38

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号