zoukankan      html  css  js  c++  java
  • DefaultNamespaceHandlerResolver中handlerMappings如何初始化

    前言:最近一直在看Spring源码,今天在调试的时候发现一个小问题:在注册bean时,需要初始化spring默认命名空间处理器,具体在DefaultNamespaceHandlerResolver中实现,但是当Debug时,发现handlerMappings已经赋值,顿感奇怪。通过调试发现了该问题产生的原因,遂记录下来。


    1.调用入口

    spring的代码调用链非常的庞大,因此阅读源码的时候,也非常耗时,这里给出创建DefaultNamespaceHandlerResolver的调用入口。

    2.Debug时出现的现象

    在上图537行处打一断点,运行后结果如下:

    注意this对象中抛出了异常,此时handlerMappings还为null,this中抛出的异常信息如下:

    此异常说明在Debug的时候,调用了toString()方法,但此时DefaultNamespaceHandlerResolver还未初始化完,所以抛出异常。猜测为IDEA另起了一个线程调用了toStirng()方法。继续调试代码。

    此时断点在构造函数括号处,程序还未执行完,此时this对象处未抛异常了,handlerMappings还为null。查看this中的信息。

    生成空间处理器的键值对。继续调试程序,退出DefaultNamespaceHandlerResolver构造函数。

    此时handlerMappings已经有9个值了,说明对其进行了初始化。根据上面的调试信息,查看DefaultNamespaceHandlerResolver的toString()方法。

    可见在toString()方法中调用了getHandlerMappings方法。

    注:该代码是不是很熟悉,使用了Double-Check的方式避免非线程安全问题,为单例模式的一种实现形式,是不是很神奇,spring源码中应用了Double-Check。

    3.个人理解

    当在DefaultNamespaceHandlerResolver初始化过程中打断点并利用IDEA进行调试的时候,IDEA会自动开启一个线程调用该类的toString方法,在本例中就对handlerMappings进行了初始化;如果正常run的方式运行,是不会出现这种情况的。

    对于重写了toString方法的类,在用Debug调试时会出现上述的情况,可写简单代码进行验证,具体代码如下:

     1 public class ToStringTest {
     2     /**
     3      * 验证Debug时,idea会开启一个线程调用对象的toString方法
     4      */
     5     public static void main(String[] args) {
     6 
     7         WilltoStringInvoked will = new WilltoStringInvoked();
     8 
     9         System.out.println("如果在这里设置断点,则输出1");
    10 
    11         System.out.println(will.getValue());
    12 
    13         System.out.println("如果不设置断点,则输出0");
    14 
    15     }
    16 
    17     static class WilltoStringInvoked {
    18         private volatile int value = 0;
    19 
    20         private int setValue() {
    21             if (value == 0) {
    22                 synchronized (this) {
    23                     if (value == 0) {
    24                         value = 1;
    25                     }
    26                 }
    27             }
    28             return value;
    29         }
    30 
    31         public int getValue() {
    32             return value;
    33         }
    34 
    35         @Override
    36         public String toString() {
    37             return "This value is:" + setValue();
    38         }
    39     }
    40 }

    在第9行处设置断点,Debug结果如下:

    如果不设置断点,调试结果如下:

    总结

    在调试spring源码的时候,最开始出现该问题觉时觉得很不可思议,后面通过不断的调试,猜测出该结论,并进行验证;同时觉得spring真的非常强大,还需继续努力,已经看了一段时间了,后面慢慢整理出来,加强印象与理解。


    by Shawn Chen,2018.11.22日,下午。

  • 相关阅读:
    Python mutilprocessing Processing 父子进程共享文件对象?
    BZOJ4836: [Lydsy1704月赛]二元运算
    博弈论刷题记录
    manacher(无讲解)
    UOJ_407_【IOI2018】狼人
    BZOJ_3935_Rbtree
    dsu on tree(无讲解)
    BZOJ_3744_Gty的妹子序列
    后缀数组(无讲解)
    虚树(无讲解)
  • 原文地址:https://www.cnblogs.com/developer_chan/p/10002492.html
Copyright © 2011-2022 走看看