动态代理中debug设置断点会执行invoke方法且args为null的原因

情景
写了个proxyExample,运行一看,竟然debug的结果跟run的结果竟然不一样,debug中会多次执行invoke方法,且并不调用sayHello方法

代码

public class ProxyExample implements InvocationHandler {
private Object target;
/**
* 创建代理,将真实对象的类、构造方法等信息告诉代理类并将代理类返回,此时代理类拥有真实类的一切,
* 甚至就可以直接看作是真实类的实例。
* @param target
* @return
*/
public Object bind(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader() , target.getClass().getInterfaces() , this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//debug:加上方法名看看调用的是什么
System.out.println("调度真实对象之前,方法名: " + method.getName() + args);
Object obj = method.invoke(target , args);
System.out.println("调度真实对象之后");
return obj;
}
public static void main(String[] args) {
ProxyExample example = new ProxyExample();
HelloWorld proxy = (HelloWorld) example.bind(new HelloWorldImpl());
proxy.sayHelloWorld();

}
}

debug运行结果
调度真实对象之前,方法名: toStringnull
调度真实对象之后
调度真实对象之前,方法名: toStringnull
调度真实对象之后
调度真实对象之前,方法名: sayHelloWorldnull
调度真实对象之前,方法名: toStringnull
调度真实对象之后
[INFO ] 2019-10-09 20:52:26 [main] [javalearning.proxytest.HelloWorldImpl] javalearning.proxytest.HelloWorldImpl.sayHelloWorld(HelloWorldImpl.java:17): Hello World!
调度真实对象之前,方法名: toStringnull
调度真实对象之后
调度真实对象之后
调度真实对象之前,方法名: toStringnull
调度真实对象之后
调度真实对象之前,方法名: toStringnull
调度真实对象之后
Disconnected from the target VM, address: '127.0.0.1:55000', transport: 'socket'

Process finished with exit code 0
run运行结果
调度真实对象之前,方法名: sayHelloWorldnull
[INFO ] 2019-10-09 21:19:41 [main] [javalearning.proxytest.HelloWorldImpl] javalearning.proxytest.HelloWorldImpl.sayHelloWorld(HelloWorldImpl.java:17): Hello World!
调度真实对象之后
Process finished with exit code 0
发现端倪
发现我单步调试时,

1.出现tostring的次数跟暂停的次数成正比,单步调试越多,invoke打印越多;

2.run模式下就没那么多打印,仅有想要的sayHello方法结果

3.如果我把断点禁用掉(把断点红色变灰的那个按钮),那么禁用之后不再打印invoke的东西,仅有sayHello方法结果

 

这样基本就能确定,多次调用invoke必定跟打断点有关系

探索
所以看看调用的到底是啥咯,也就是上面代码中的这一行:

//debug加上方法名看看调用的是什么
System.out.println("调度真实对象之前,方法名: " + method.getName() + args);
可以看到打印结果,被调用的方法名是tostring,猜是idea中debug程序自带的问题,以下是引用内容,

鸣谢lkforce:

断点处暂停时,IDEA会调用被代理类的toString()方法获取相关信息,鼠标悬停显示的好像就是那个东西。由于代理类代理该类的所有方法(包括toString),因此暂停一次就会输出一次“调用了toString()方法”的相关信息

多数情况下调用一下toString()方法没有什么问题,但是也有例外,比如重写了toString()方法的类,随意的调用toString()方法会导致未知的问题,比如Dubbo的AbstractConfig类,对这个类的debug会导致其子类ReferenceConfig的initialized属性错误的被修改为true,进而无法正确的生成Dubbo代理。

另外,IDEA在debug时调用toString()方法的情况是可以在配置中关掉的,配置位置是

Settings->Build,Execution,Development->Debugger->Java->Enable ‘toString()’ object view

 

https://blog.csdn.net/q2878948/article/details/102491389

posted on 2024-03-05 13:45  怦然丶心动  阅读(28)  评论(0编辑  收藏  举报