Java动态代理(含invoke中死循环问题)

原创 2015年11月20日 10:37:52

声明:①本文代码参考《think in Java》第四版,14章第7节SimpleDynamicProxy.java代码做了改进。
②本文参考了JDK1.5 API文档。
代码如下:

package cn.edu.beike.kivi.typeinfo.level1;

// SimpleDynamicProxy.java
// Inside invoke() in SimpleDynamicProxy.java, try to print the proxy argument and explain
// what happens.
import java.lang.reflect.*;

interface Interface {
    void doSomething();
    void somethingElse(String arg);
}

class RealObject implements Interface {
    public void doSomething() { print("doSomething"); }
    public void somethingElse(String arg) {
        print("somethingElse " + arg);
    }
}

class DynamicProxyHandler implements InvocationHandler {
    private Object proxied;
    private static int count=0;
    public DynamicProxyHandler(Object proxied) {
        this.proxied = proxied;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if(count<4)
        {   
            count++;
            System.out.println("DynamicProxyHandler.invoke()————proxy类名获取: " +proxy.getClass()); 
            System.out.println("proxy.toString():"+proxy.toString());
        }
        return method.invoke(proxied, args);
    }
}

class SimpleDynamicProxy {
    public static void consumer(Interface iface) {
        iface.doSomething();
    }
    public static void main(String[] args) {
        RealObject real = new RealObject();
        Interface proxy = (Interface)Proxy.newProxyInstance(
            Interface.class.getClassLoader(),
            new Class[]{ Interface.class },
            new DynamicProxyHandler(real));
        System.out.println("Main()————proxy类名获取"+proxy.getClass());
        consumer(proxy);        
    }
}

运行结果如下:

Main()————proxy类名获取class cn.edu.beike.kivi.typeinfo.level1.$Proxy0
DynamicProxyHandler.invoke()————proxy类名获取: class cn.edu.beike.kivi.typeinfo.level1.$Proxy0
DynamicProxyHandler.invoke()————proxy类名获取: class cn.edu.beike.kivi.typeinfo.level1.$Proxy0
DynamicProxyHandler.invoke()————proxy类名获取: class cn.edu.beike.kivi.typeinfo.level1.$Proxy0
DynamicProxyHandler.invoke()————proxy类名获取: class cn.edu.beike.kivi.typeinfo.level1.$Proxy0
proxy.toString():cn.edu.beike.kivi.typeinfo.level1.RealObject@be7f971
proxy.toString():cn.edu.beike.kivi.typeinfo.level1.RealObject@be7f971
proxy.toString():cn.edu.beike.kivi.typeinfo.level1.RealObject@be7f971
proxy.toString():cn.edu.beike.kivi.typeinfo.level1.RealObject@be7f971
doSomething

代码更改测试:

若将DynamicProxyHandler类中invoke中proxy.toString()的输出注释掉:

    //System.out.println("proxy.toString():"+proxy.toString());

则运行结果如下:

Main()————proxy类名获取class cn.edu.beike.kivi.typeinfo.level1.$Proxy0
DynamicProxyHandler.invoke()————proxy类名获取: class cn.edu.beike.kivi.typeinfo.level1.$Proxy0
doSomething

代码解析:
类及接口解析:
⑴Interface: ①被代理类(RealObject类)实现的接口
②它的Class对象是实例化代理类时需要传递的参数(Proxy.newProxyInstance()中第二个参数)。
⑵RealObject:被代理类
⑶Proxy:代理类
proxy=Poxy.newInstance(…):代理类对象(通过Proxy类的静态实例化方法创建)
⑷DynamicProxyHandler:实现InvocationHandler接口的类,通常被称为调用处理器。

1.动态代理中需关注如下的类和接口及其方法:
①Proxy类;
②Proxy类中的方法:newProxyInstance();

public static Object newProxyInstance(    
             ClassLoader    loader,
             Class<?>[]        interfaces,
             InvocationHandler  h)
    throws IllegalArgumentException`

③InvocationHandler接口;
④InvocationHandler接口的方法:invoke();

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

2.Proxy.newProxyInstance()中三个参数详解:
①ClassLoader loader : 定义代理类的类加载器,可获得已知的加载器。
②Class<?> interfaces : 希望代理代理实现的接口列表,它可以是多个接口。
③InvocationHandler h : InvocationHandler接口的一个具体实现类的对象的引用(需传入被代理类实例对象的引用)。
如下代码:real既是RealObject的实例对象的引用

new DynamicProxyHandler(real);

3.InvocationHandler实现类【即上面代码中DynamicProxyHandler类】中invoke()函数及相关参数详解
①Object proxy:代理对象引用(即main函数中创建的proxy的引用,通过在main,invoke两函数中输出对象信息可证明,如以上代码及结果所示)——谨慎使用,防止无限递归而陷入死循环。
②Method method:代理类中接受的接口方法。
③Object[] args:向代理对象的方法中传递的参数。
例如:proxy.doSomething(strings); 中proxy即代理对象;doSomething()即代理类中接受的接口方法;strings即传递的参数。

4.动态代理机制:
当通过代理对象proxy调用方法时:proxy.doSomething();
都将会被重定向到DynamicProxyHandler类对象(调用处理器)的invoke()函数。
即,若在invoke()函数中使用proxy调用方法会陷入死循环,如以上代码结果所示。

然而有趣的是:
invoke()中proxy.getClass()并不会触发动态代理。
它输出的是接口的Class对象,而不是被代理类的Class对象。

版权声明:本文为博主原创文章,未经博主允许不得转载。

java实现动态代理代码实例(死循环溢出的问题的解决)

本文介绍了java方法模拟动态代理,开始时老是因为把代理类的对象传入invoke方法使用陷入死循环。具体死循环的原因会再整理下再发一篇。...

InvocationHandler中invoke方法中的第一个参数proxy的用途

最近在研究Java的动态代理时对invoke函数的第一个参数一直不理解它的用处,某度搜索也搜不出结果,最后终于在stackoverflow上找到了答案。 这是原文的链接:http://stackove...
  • bu2_int
  • bu2_int
  • 2017年03月03日 21:25
  • 1464

Spring循环引用和AOP代理引发的两个问题

暂作记录:     1.
  • Yoara
  • Yoara
  • 2014年10月08日 14:48
  • 1861

java动态代理中的invoke方法是如何被自动调用的

转载声明:本文转载至 zcc_0015的专栏 一、动态代理与静态代理的区别。 (1)Proxy类的代码被固定下来,不会因为业务的逐渐庞大而庞大; (2)可以实现AOP编程,这是静态代理无法实现的;...

java动态代理中的invoke方法是如何被自动调用的

Java中动态代理的实现,关键就是这两个东西:Proxy、InvocationHandler,下面从InvocationHandler接口中的invoke方法入手,简单说明一下Java如何实现动态代理...

动态代理proxy与CGLib的区别

 动态代理与CGlib的区别,回顾一下: 什么是代理?静态代理与动态代理静态代理实例JDK动态代理实例CGLib 简介CGLib 与JDK动态代理的区别     代理模式是Jav...

cglib简单的小实例

cglib和Jdk的动态代理相比,它的优点是目标类不用实现一个接口。 代码实现: 目标类 package cglib; public class ClassHasNoInter...

JDK动态代理中关于InvocationHandler中invoke()方法的调用问题

ava中动态代理的实现,关键就是这两个东西:Proxy、InvocationHandler,下面从InvocationHandler接口中的invoke方法入手,简单说明一下Java如何实现动态代理的...
  • hll174
  • hll174
  • 2015年12月01日 10:09
  • 298

spring动态代理的实现原理InvocationHandler中invoke()方法的调用问题

以下的内容参考了网络上的内容,在此对原作者表示感谢!          Java中动态代理的实现,关键就是这两个东西:Proxy、InvocationHandler,下面从InvocationH...

java动态代理中的invoke方法是如何被自动调用的

一、动态代理与静态代理的区别。(1)Proxy类的代码被固定下来,不会因为业务的逐渐庞大而庞大;(2)可以实现AOP编程,这是静态代理无法实现的;(3)解耦,如果用在web业务下,可以实现数据层和业务...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java动态代理(含invoke中死循环问题)
举报原因:
原因补充:

(最多只允许输入30个字)