阅读 8

dubbo debug过程中发现的IDEA有趣的小发现及dubbo消费者debug小tips

本来是在debug dubbo的reference bean的init()过程,因为ReferenceBean是继承了Spring FactoryBean接口的,

所以初始化入口自然就是FactoryBean定义的函数,getObject()。在该方法内,只显示调用了ReferenceConfig.get()。

内容如下:

public synchronized 
复制代码

可以看到,核心的初始化代码就在init()中。这里,会首先判断factoryBean 要创建的bean实例ref是否已经初始化,若未初始化,才会进行Init()调用。

所以,我断点自然就打在ReferenceBean.getObject()上。

启动spring。

反复多次,我发现,只要我在ReferenceBean.getObject()或者ReferenceConfig.get()上加上断点,ref实例就会莫名其妙地已经被初始化过,proxy$xxxx。

这就奇怪了。

这个ReferenceBean的整个的入口函数,getObject()的触发,是在我的控制下的啊,即:

springContext.getBean("referenceBeanId");

那我就在想,是不是spring container的初始化有异步的部分呢?所以我就直接把断点加载init()方法上。

然后我返回调试后发现,如果我只将断点加在Init(),而ReferenceBean.getObject()与ReferenceConfig.get()不加断点的话,init()方法里是正常进入,且进入的代码initialized也是false的

private void 
复制代码
}
复制代码
就是init()开头4行代码处。
后来我就想,是不是哪里给反射注入了呢?当然,我也没啥发现,我就直接百度了。结果果不其然。
在网上发现了一篇同样问的文章。那个人在源码里加了一段注释,如下

图片已损坏

图片已损坏

可以看到,AbstractConfig.toString()方法竟然反射调用了ReferenceConfig.init()方法。。。

AbstractConfig.toString()的代码如下:

image

可以看到,这个if里是对所有getter通过的,通过后,又再接下来的红框处调用了我擦,也就是说,ReferenceBean.getObject()给调用了,进而也就init()给调用了。

后来,原文作者又做了这样一个测试,得出了最终结果

图片已损坏

结果就是:

IDEA这类编辑器的debug功能为了在断点处能够显示类实例的相关信息,就会反射调用相关类实例的toString()方法!!!!

思考:

DUBBO为什么要在AbstractConfig.toString()的反射调用init()呢?真尼玛奇怪。。。。

答案:

dubbo的AbstractConfig的toString方法反射调用只是为了输出时能够更全面一点。但是因为AbstractConfig的子类

ReferenceBean实现了FactoryBean接口,这个接口是Spring用来获取Bean实例的工厂bean,生成bean的方法就叫getObject,正好符合了toString里面逻辑,而getObject里是要初始化bean的。所以,就这么巧地对应上了

关注下面的标签,发现更多相似文章
评论