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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/q99261581/article/details/49944003

Java并发之不可思议的死循环

下面的代码将发生死循环:package com.zzj.concurrency; public class VolatileObjectTest implements Runnable{ priv...
  • zhangzeyuaaa
  • zhangzeyuaaa
  • 2016-12-10 23:18:29
  • 1302

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

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

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

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

Java事务(五) - 使用动态代理改造

一. 前言: 在上一篇博文中, 我们使用模板模式进行事务管理, 代码看起来已经很简洁了, 但是还是不太完美, 我们依然需要在service层编写和事务相关的代码, 即我们需要在service层宗声明...
  • zdp072
  • zdp072
  • 2014-09-13 14:02:34
  • 1294

【Java基础】动态代理实现AOP之控制事务

前言在学习设计模式的时候,对静态代理和动态代理做过研究,静态代理倒是很好理解,代码也简单。但是动态代理代码相对复杂,基于当时的水平,没看太懂。这次就来解析一下java中的动态代理。 静态代理缺点静态...
  • u010028869
  • u010028869
  • 2016-01-12 15:22:30
  • 2011

Java事务处理全解析(六)—— 使用动态代理(Dynamic Proxy)完成事务

在本系列的上一篇文章中,我们讲到了使用Template模式进行事务管理,这固然是一种很好的方法,但是不那么完美的地方在于我们依然需要在service层中编写和事务处理相关的代码,即我们需要在servi...
  • huilangeliuxin
  • huilangeliuxin
  • 2015-02-03 11:05:20
  • 8142

一个悲惨的程序的故事:死循环。循环的注意(1)

这里有一个悲惨的程序:#include using namespace std; int main() { int n; while(n) { cout...
  • xhyds
  • xhyds
  • 2017-05-07 13:27:15
  • 297

动态代理(了解但不常用)

package com.util; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; impo...
  • Aurora_sss
  • Aurora_sss
  • 2017-05-04 21:52:40
  • 182

警惕动态代理导致的Metaspace内存泄漏问题

前一段时间,公司将jdk升级到1.8之后,系统出现问题,问题集中在系统中包含的两个服务上。通过监控发现,每过十五分钟,这两个服务所在的服务器的内存就会减少,不到一天的时间,整个服务器的内存就被耗光,导...
  • xyghehehehe
  • xyghehehehe
  • 2017-12-16 15:25:45
  • 153

java 递归详解

刚学java的时候通常难以理解递归程序设计的概念。递归思想之所以困难,原因在于它非常像是循环推理(circular reasoning)。它也不是一个直观的过程;当我们指挥别人做事的时候,我们极少会递...
  • qq_14996421
  • qq_14996421
  • 2016-04-29 11:50:57
  • 3974
收藏助手
不良信息举报
您举报文章:Java动态代理(含invoke中死循环问题)
举报原因:
原因补充:

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