`
825197453
  • 浏览: 101099 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

InvocationHandler接口

阅读更多
InvocationHandler接口2009-05-13 11:23动态代理是很多框架和技术的基础, 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("this is 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
this is 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参数应该是这样一个用意吧。

分享到:
评论

相关推荐

    java静态代理和动态代理详解

    Java中提供了一个java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现动态代理。代理类在运行时会根据被代理接口自动生成,并且可以通过InvocationHandler接口对方法进行增强。

    AOP的动态代理proxy

    1. 首先完成一个接口的创建(里面有真正的想要实现的方法): public interface UserDAO{ public void add (); //想要实现的方法 } 2. 写一个真实的主题类实现...3. 写一个动态的代理类实现InvocationHandler接口:

    Java SSM框架集成的日志功能增强Demo源码

    项目名称:Java SSM框架集成日志功能增强Demo 主要编程语言:Java ...项目利用Java动态代理机制,通过实现InvocationHandler接口,巧妙地运用AOP(面向切面编程)实现了日志功能,增强了应用的可追踪性与维护性。

    java 实现AOP

     JDK1.2以后提供了动态代理的支持,程序员通过实现java.lang.reflect.InvocationHandler接口提供一个执行处理器,然后通过java.lang.reflect.Proxy得到一个代理对象,通过这个代理对象来执行商业方法,在商业方法被...

    JAVA设计模式(动态代理)

    当系统有了一个代理对象后,对源对象的方法调用会首先被分派给一个调用处理器(InvocationHandler)//接口InvocationHandler接口中有一个invoke()方法 程序可以在调用处理器的invoke方法中截获这个调用,进行额外...

    Java动态代理1

    动态代理的实现:一:简单的动态代理实现:(1) 实现InvocationHandler接口(2) Proxy.newInstance()创建代理例:二:实际案

    Java面向对象系列[v1.0.0][使用反射生成动态代理]

    在Java的java.lang.reflect包里有个Proxy类和一个InvocationHandler接口,通过使用他们可以生成JDK动态代理类或动态代理对象 使用Proxy和InvocationHandler创建动态代理 Proxy提供了用于创建动态代理类和代理对象的...

    ProxyTest.zip

    Java动静态代理机制简介,尤其是动态代理,结合反射机制,为后续的java hook技术打下基础。动态代理需实现java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持。

    Java典型模块

    3.7.3 InvocationHandler接口 3.7.4 动态代理类的设计模式 3.8 小结 第2篇 线程开发 第4章 学生并发接水(线程Thread) 4.1 学生并发接水原理 4.1.1 项目结构框架分析 4.1.2 项目功能业务分析 4.2 不排队形式学生...

    java实现Proxy例子

    我自己用eclipse写的java代码,可以直接用eclipse导入,也可以直接用java -jar proxy_sample.jar执行 ...本例实现了InvocationHandler接口,代码具有典型性 在研究代理模式(Proxy模式)的朋友可以交流一下

    JDK动态代理+JDK动态代理完整代码+JDK动态代理代码实现逻辑

    动态代理::在程序运行时,运用反射机制动态创建而成。 动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员...java.lang.reflect 包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。

    AOP的实现机制

    使用动态代理实现AOP需要有四个角色:被代理的类,被代理类的接口,织入器,和InvocationHandler,而织入器使用接口反射机制生成一个代理类,然后在这个代理类中织入代码。被代理的类是AOP里所说的目标,...

    Java_AOP.zip_AOP ja

    Java通过一个类Proxy以及一个接口InvocationHandler来实现函数接管的功能,这两个类都是在java.lang.reflect包中。 对接管对象如本例中的TestProxy的要求: 必须实现接口InvocationHandler。 需要保存原有接口的...

    spring代码课堂笔记

    InvocationHandler实现类的实例对象 Spring AOP:简化代理模式实现步骤 1.声明接口:注册需要被监听行为名称 2.接口实现类: 扮演被监控的类,负责被监听方法实现细节 3.次要业务/增强业务 Spring AOP 通知...

    使用Java动态代理实现一个简单的网络请求拦截器.txt

    在这个例子中,我们创建了一个`HttpRequestInterceptor`类来实现`InvocationHandler`接口,并在`invoke()`方法中实现了对目标方法的拦截操作。在`main()`方法中,我们首先创建了一个`HttpURLConnection`对象来发送...

    接口--内部类--多继承

    演示程序 博文链接:https://invocationhandler.iteye.com/blog/1581128

    com-spring-ioc-demo:源码主要是学习Spring IOC的原理,以及对Bean的注册及控制,主要运用以下类对Spring进行扩展学习:BeanPostProcessor,BeanFactoryAware,BeanNameAware,ApplicationContextAware,FactoryBean,BeanDefinitionRegistryPostProcessor,BeanFactoryPostProcessor,BeanPostProcessor,ResourceLoaderA

    BeanDefinitionRegistryPostProcessor,BeanFactoryPostProcessor,BeanPostProcessor,ResourceLoaderAware,InvocationHandler。 BeanPostProcessor接口的实现类如何被注册到Spring容器2.更改bean的定义...

    MyBatis简介.docx

    Mybatis 仅可以编写针对 ParameterHandler 、ResultSetHandler 、StatementHandler 、 Executor 这 4 种接口的插件, Mybatis 通过动态代理,为需要拦截的接口生成代理对象以实 现接口方法拦截功能,每当执行这 4 种...

Global site tag (gtag.js) - Google Analytics