zoukankan      html  css  js  c++  java
  • dubbo debug过程中一个有趣的问题

    最近在debug dubbo代码过程中遇到的很有趣的问题

    我们都知道dubbo ReferenceBean是消费者的spring bean包装,为了查一个consumer端的问题,在ReferenceBean的父类ReferenceConfig的 T get()方法(140行)打上了一个断点。

    当我debug 跟进init方法之后发现,ReferenceConfig的成员变量initialized(boolean类型),没有初始化,值变成了true? 纳尼。。。
    在学习java的基础知识的时候,我们就知道如果boolean类型如果不初始化变量,运行的时候默认初始为true。为什么变量initialized没有赋值的情况,值是true呢?

    更奇怪的是,debug模式下,因为initialized=true consumer的桩代码(proxy)没有生成,所以在业务层调用的时候跑出了NPE;但是在run模式下是对的。

    初步怀疑

    初步怀疑是debug模式和run模式下初始化的值是不同的,然后上google去搜索一下是不是存在这个问题,可惜没有任何的收获;同时在初始化的时候,直接把initialized初始化为false,防止缺省值初始成true。
    但是问题依旧,放弃了这条思路!!!
    然后开始怀疑是IDEA编辑器是不是在断点处有setvalue的情况,就把IDEA全部缓存清空并重启了(File->Invalidate....),debug后问题依然!!!

    修改dubbo的源代码加日志输出

    实在没什么思路了,想着先去增加一些日志输出,办法虽然很土,但是可能会有线索。在initialized=true 这行代码之后加一行输出
    System.out.println("init initialized="+initialized);

    同时断点还在ReferenceConfig.get()方法里面

    当运行到断点出,观察console的输出,果然有输出!!!!

    这说明当我断点在ReferenceConfig.get()方法里时候,有线程执行了init()方法导致initialized的值被修改成了true(dubbo代码只有一处修改ReferenceConfig.initialized值的地方,就在init里面)
    所以只要找出哪个线程在我断点的时候,执行了init方法就行了

    日志输出又立大功

    继续在init方法里面加日志输出,以下日志能显示出哪个堆栈调用了init方法

    继续debug运行,得到结果出乎意外

    从日志输出可以看出来,在ReferenceConfig构造函数的地方,调用了父类AbstractConfig.toString方法,而在AbstractConfig的toString方法里面反射间接调用了ReferenceConfig.init()方法
    这下算是找到谁在我断点的时候调用了ReferenceConfig.init()方法,就是toString()方法。
    但是谁调用了toString()方法呢?

    真想大白

    首先可以排除程序在构造函数里面调用AbstractConfig.toString方法,还有一种可能就是IDEA 为了显示触发了这个类实例的toString方法。有了这个假设思路,写了一个demo验证一下

    果不其然console里面输出了invoke toString()

    总结

    IDEA 这类编辑器带debug功能为了断点处能显示一个类的实例,就会反射调用实例的toString!!!!
    真是一个有趣的发现!!!!

    附送dubbo ReferenceConfig源码链接

  • 相关阅读:
    函数对象中的prototype属性
    undefined和null的区别
    访问修饰符
    继承
    静态成员和实例成员的区别
    js模拟Trim()方法
    连接池的执行原理
    Javascript中的= =(等于)与= = =(全等于)区别
    数据库中创建约束
    KM算法入门
  • 原文地址:https://www.cnblogs.com/oldtrafford/p/8612089.html
Copyright © 2011-2022 走看看