`
kuersike
  • 浏览: 1650 次
  • 性别: Icon_minigender_1
  • 来自: 成都
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

动态代理之:接口InvocationHandler

阅读更多
前段时间学习JDBC过程中碰到动态代理的相关知识,做测试过程中不能理解接口InvocationHandler 中方法:public Object invoke(Object proxy, Method method, Object[] args) throws Throwable的参数Object proxy做何用,关于动态代理的相关知识就不在此赘述了,现将自己的例子附上,请大家看看参考。

1.接口:
public interface IUser {
public String getName();
}
2.接口对应的类:
public class UserImp implements IUser {
String name;
public UserImp(String name){
this.name = name;
}
public String getName() {
return name;
}

}
3.监听方法所在类,该类实现了InvocationHandler 接口,通过invoke方法利用java的反射机制实现对相关方法的监听。
public class Handler implements InvocationHandler {


public Object targetObj;


public Handler(Object targetObj) {
this.targetObj = targetObj;
}

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

System.out.println("before the function \""+method.getName()+"\"");
Object ret = method.invoke(targetObj, args);
System.out.println(ret);
System.out.println("after the function \""+method.getName()+"\"");

}

}
4.测试方法:
public class testMain {

public static void main(String[] args) {

IUser realUser = new UserImp("sun");
Handler hand = new Handler(realUser);
IUser proxy = (IUser) Proxy.newProxyInstance(realUser.getClass().getClassLoader(), realUser.getClass().getInterfaces(), hand);
proxy.getName();
}

}
5.输出结果:
before the function "getName"
sun
after the function "getName"


疑问:在步骤3中invoke(Object proxy, Method method, Object[] args)方法的参数proxy的作用是什么,如何使用?
在论坛中看到大家发帖讲述的该参数的作用为:proxy就是你调用的代理
java doc中的说明为:proxy - 在其上调用方法的代理实例

按照上面的叙述,是否可以将步骤3的代码改成如下的形式:
public class Handler implements InvocationHandler {

/*
public Object targetObj;


public Handler(Object targetObj) {
this.targetObj = targetObj;
}
*/

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

System.out.println("before the function \""+method.getName()+"\"");
Object ret = method.invoke(proxy, args);
System.out.println(ret);
System.out.println("after the function \""+method.getName()+"\"");

}

}

但是改成这样后程序好像进入了死循环一样,如下是输出结果:

at Handler.invoke(Handler.java:27)
at $Proxy0.getName(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at Handler.invoke(Handler.java:27)
at $Proxy0.getName(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at Handler.invoke(Handler.java:27)


请各位帮忙答疑!
谢谢!
分享到:
评论
4 楼 kingsword 2011-09-03  
楼主很细心,欧也有点搞不懂这个proxy参数,留在那里的,感觉又没什么用,至少对于参与切片的业务逻辑来说不会用。如是为了支持动态代理的内部机制工作的话,把这个proxy参数留在那里,感觉从设计上也挺怪的。
3 楼 mikewang 2009-04-13  
proxy 是你在创建代理的时候有jvm生产的字节码, 文档上已经说的很清楚了, 保证这个proxy 可以转化成你的interface , 但没说这个proxy 就一定是一个可以执行的class

我的理解是 这里的 proxy 类似一个智能指针, 他的作用只不过 可以让jvm从这个指针中的到真正可以执行的代码的位置(就是的hander), 和 函数名称, 参数等信息而已

这点可以从  Proxy.newProxyInstance 的源代码中可以得到证实, 这个函数主要就是调用 getProxyClass 这个函数来创建代理类(也就是你的proxy)

分析这个 getProxyClass 函数, 他做的工作就是
1 整理你需要代理的接口
2 得到每个接口的方法, 参数等信息
3 把每个接口的方法,缓存一下(放到一个map里面, 估计是等到调用的时候, 方便找到)

4 最重要的, 生成proxy  注意, 这里的proxy 核心的部分 就是 刚才说的那个缓存 方法的map

5 最后返回,你要的接口。(这里也不需要判断了, 反正,最后也是你自己在hander里面处理, 只要有方法的名称就可以了)

proxy的执行顺序就是 根据接口找到 函数, 然后在map中找到函数真正的可以执行的代码, 然后在调用传到hander中去执行调用(这步由你完成),实际上就是 5 -> 4 -> 3 -> 2 所以可以看出, proxy 就是我刚才说的, 类似一个智能指针而已。
2 楼 kuersike 2009-04-13  
mikewang 写道
没错呀, 自己代理自己, 当然是死循环了。

好像是这么回事,不过这个参数一般如何使用啊。
如果在invoke方法中加入打印它的代码都会出错呢:System.out.println(proxy);

报错如下:
java.lang.StackOverflowError
at Handler.invoke(Handler.java:18)
at $Proxy0.toString(Unknown Source)
at java.lang.String.valueOf(String.java:2131)
at java.io.PrintStream.print(PrintStream.java:462)
at java.io.PrintStream.println(PrintStream.java:599)
at Handler.invoke(Handler.java:18)
at $Proxy0.toString(Unknown Source)
at java.lang.String.valueOf(String.java:2131)
at java.io.PrintStream.print(PrintStream.java:462)
at java.io.PrintStream.println(PrintStream.java:599)
at Handler.invoke(Handler.java:18)

开始以为在执行这段代码时会将真实对象的参数传递到invoke中的proxy参数的:
IUser proxy = (IUser) Proxy.newProxyInstance(realUser.getClass().getClassLoader(), realUser.getClass().getInterfaces(), hand);

这样的话在实现InvocationHandler接口时必须提供传递真实类的方法,也就是上面例子中的:
public Object targetObj;


public Handler(Object targetObj) {
this.targetObj = targetObj;
}

这个和普通的实现接口不一样哈!

1 楼 mikewang 2009-04-13  
没错呀, 自己代理自己, 当然是死循环了。

相关推荐

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

    Java中的代理是一种常见的设计模式,它可以帮助我们在不改变原有代码逻辑的情况下,对现有对象进行增强或扩展。...代理类在运行时会根据被代理接口自动生成,并且可以通过InvocationHandler接口对方法进行增强。

    Java动态代理1

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

    AOP的动态代理proxy

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

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

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

    java动态代理和反射

    java动态代理 public class HireProxy implements InvocationHandler { //被代理的真实角色 private Object obj; public HireProxy(Object obj) { super(); this.obj = obj; } //第二个参数method,被...

    AOP的实现机制

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

    JDK的动态代理(powernode 文档)(源代码)

    JDK的动态代理(powernode 文档)(源代码) JDK的动态代理(powernode 文档) 一、动态代理 1.1JDK动态代理 1.1.1 proxy 1.1.2 InvocationHandler 1.1.3 创建一个Maven项目 1.1.4 导入Spring的相关依赖 1.1.5 修改...

    JDK动态代理(powernode CD2207 video)(教学视频+源代码)

    JDK动态代理(powernode CD2207 video)(教学视频+源代码) JDK动态代理(powernode CD2207 video) 一、动态代理 1.1JDK动态代理 1.1.1 proxy 1.1.2 InvocationHandler 1.1.3 创建一个Maven项目 1.1.4 导入Spring...

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

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

    JAVA设计模式(动态代理)

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

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

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

    Java的动态代理机制详解

     在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。首先我们先来看看java的API帮助文档是怎么样对...

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

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

    demo:java生产项目常用的demo

    使用jdk proxy代理接口方式实现 使用Cglib代理类方式实现 自己实现的动态代理 模仿jdk proxy自己实现动态代理: 核心:实现动态代理的Proxy类 , 实现动态代理的InvocationHandler类重写invoke方法实现. 二.spring 1...

    spring代码课堂笔记

    Spring AOP Advice接口:只能对当前接口下所有的实现类进行次要业务绑定执行,无法动态指定 Spring AOP Advisor:(顾问) 1.一种织入方式 2.实际上Adivce封装版。 3.可以动态的将切面指定对应切入点 Spring...

    Java_AOP.zip_AOP ja

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

    ProxyTest.zip

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

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

    com-spring-ioc-demo:源码主要是学习Spring IOC的原理,以及对Bean的注册及控制,主要运用以下类对...通过FactoryBean结合InvocationHandler关于动态代理invoke()方法的理解5.BeanNameAware 7.BeanFactoryPostPro

    MyBatis简介.docx

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

    java 实现AOP

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

Global site tag (gtag.js) - Google Analytics