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对象。

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

相关文章推荐

spring的AOP(二)----JDK动态代理

JDK动态代理在1.3的时候引入,其底层需要依赖一个工具类java.lang.reflect.Proxy和一个接口java.lang.reflect.InvocationHandlerJDK 动态代理...

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

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

java动态代理的两种实现方式

一说到动态代理,我们第一个想到肯定是大名鼎鼎的Spring AOP了。在AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。两种方法同时存在,各有优劣。jdk动态...

一个小demo

一个小demo,想封装成一个可复用的类似插件,或者是推翻重写,其实就是想看看高质量代码 1 DOCTYPE html> 2 html> 3 4 head> ...

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

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

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

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

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

以下的内容参考了网络上的内容,在此对原作者表示感谢!          Java中动态代理的实现,关键就是这两个东西:Proxy、InvocationHandler,下面从InvocationH...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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