前言:最近一直在看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调试时会出现上述的情况,可写简单代码进行验证,具体代码如下:

 public class ToStringTest {
/**
* 验证Debug时,idea会开启一个线程调用对象的toString方法
*/
public static void main(String[] args) { WilltoStringInvoked will = new WilltoStringInvoked(); System.out.println("如果在这里设置断点,则输出1"); System.out.println(will.getValue()); System.out.println("如果不设置断点,则输出0"); } static class WilltoStringInvoked {
private volatile int value = 0; private int setValue() {
if (value == 0) {
synchronized (this) {
if (value == 0) {
value = 1;
}
}
}
return value;
} public int getValue() {
return value;
} @Override
public String toString() {
return "This value is:" + setValue();
}
}
}

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

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

总结

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


by Shawn Chen,2018.11.22日,下午。

DefaultNamespaceHandlerResolver中handlerMappings如何初始化的更多相关文章

  1. c++ 类与函数中static变量初始化问题(转)

    首先static变量只有一次初始化,不管在类中还是在函数中..有这样一个函数: void Foo() { ; // initialize std::cout << a; a++; } 里的 ...

  2. 49.关于Quartus和ISE中ROM的初始化和仿真的一些小结

    最近在玩Altera的FPGA,当我用Quartus II自带的IP核生成ROM时,出现了各种问题,于是在网上各种查资料,终于解决了我的问题.这里做一下小结,方便自己日后查阅. Quartus II ...

  3. Python中,如何初始化不同的变量类型为空值

    参考文章  Python中,如何初始化不同的变量类型为空值 常见的数字,字符,很简单,不多解释. 列表List的其值是[x,y,z]的形式 字典Dictionary的值是{x:a, y:b, z:c} ...

  4. Java中的成员初始化顺序和内存分配过程

    Java中的成员初始化顺序和内存分配过程 原帖是这样描述的: http://java.dzone.com/articles/java-object-initialization?utm_source= ...

  5. Java中数组的初始化方式

    Java中数组的初始化方式    初始化方式有两种: 1.静态初始化:初始化时由程序猿显式指定每一个数组元素的初始值,由系统指定数组长度 2.动态初始化:初始化时由程序猿仅仅指定数组长度,由系统为数组 ...

  6. java中的静态初始化块

    Java 中可以通过初始化块进行数据赋值.如: 在类的声明中,可以包含多个初始化块,当创建类的实例时,就会依次执行这些代码块.如果使用 static 修饰初始化块,就称为静态初始化块. 需要特别注意: ...

  7. Hive_UDF函数中集合对象初始化的注意事项

    UDF函数中定义的集合对象何时初始化 udf函数放在sql中对某个字段进行处理,那么在底层会创建一个该类的对象,这个对象不断的去调用这个evaluate(...)方法,截图如下:   1.1 如果说对 ...

  8. c++构造函数成员初始化中赋值和初始化列表两种方式的区别

    先总结下: 由于类成员初始化总在构造函数执行之前 1)从必要性: a. 成员是类或结构,且构造函数带参数:成员初始化时无法调用缺省(无参)构造函数 b. 成员是常量或引用:成员无法赋值,只能被初始化 ...

  9. C++中的对象初始化

    当对象在创建时获得了一个特定的值,我们说这个对象被初始化.初始化不是赋值,初始化的含义是创建变量赋予其一个初始值,而赋值的含义是把当前值擦除,而以一个新值来替代.对象初始化可以分为默认初始化.直接初始 ...

随机推荐

  1. [C#] C# 知识回顾 - Lambda

    C# 知识回顾 - Lambda 序 它是第十一个希腊字母,一个拥有失意.无奈.孤独.低调等含义的流行符号,也指示一款称为“半条命”的游戏. 不过,这次我所讲的是 C# 中的 Lambda. 目录 L ...

  2. petapoco 实体中字段去掉关联(类似于EF中的NotMap)

    怎么才能让不是数据库表中的字段放在实体中而不影响正常的插入和更新呢? 找到 PetaPoco.cs 文件,打开之后,搜索插入方法(Insert),然后继续找到下一层方法 就能看到如下代码: 看到这个注 ...

  3. clean 伪目标

    下面的"clean"目标,是一个"伪目标",      clean:              rm *.o temp  我们生成了许多文件编译文件,我们也应该 ...

  4. github 遇到的问题

    目录 1.遇到的问题关联远程仓库,操作顺序如下:2.解决方法3.git merge 与 git rebase4.git pull 与 git pull --rebase5.更多参考 博客逐步迁移至 极 ...

  5. JavaScript解析机制与闭包原理实例详解

    js代码解析机制: js代码解析之前会创建一个如下的词法环境对象(仓库):LexicalEnvironment{ } 在扫描js代码时会把: 1.用声明的方式创建的函数的名字; 2.用var定义的变量 ...

  6. CSS3的媒体查询(Media Queries)与移动设备显示尺寸大全

    媒体查询介绍 我今天就总结一下响应式设计的核心CSS技术Media(媒体查询器)的用法. 先看一个简单的例子: <link rel="stylesheet" media=&q ...

  7. 【代码笔记】Web-Javascript-Javascript typeof

    一,效果图. 二,代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  8. SAP MM PO 中的Delivery Date并非保存在EKPO表里

    采购订单行项目中的deliverydate并非如同其它字段值一样是保存在采购订单行项目表EKPO里的, 而是从EKET表里抓取最早的Delivery Date作为该Item的delivery date ...

  9. loadrunner 脚本录制-Action分类

    脚本录制-Action分类 by:授客 QQ:1033553122 Action分类 l . Vuser_init 2. Vuser_end 3.  Action 在lr中用户的初始化操作应该存放在V ...

  10. Android P的APP适配总结,让你快人一步

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由QQ音乐技术团队发表于云+社区专栏 上篇:Android P 行为变更适配 Android P 这次有很多行为变更,其中不乏一些需要亟 ...