关闭

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

标签: java死循环动态代理invoke
1187人阅读 评论(0) 收藏 举报
分类:

声明:①本文代码参考《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对象。

3
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:4354次
    • 积分:171
    • 等级:
    • 排名:千里之外
    • 原创:13篇
    • 转载:1篇
    • 译文:0篇
    • 评论:0条