美文网首页Java 杂谈Spring-Boot
慌了!本地可以跑的项目,一上线就崩?

慌了!本地可以跑的项目,一上线就崩?

作者: 70b39f9dc443 | 来源:发表于2019-06-03 15:22 被阅读0次

    上周,好友反馈了一个问题,他们项目在本地是可以跑的,但是在线上环境,就报错.报错日志如下:

    说实话,每天这么忙,看到这种直接丢个异常出来的根本不想理.但是他一句话彻底改变了我的想法.

    首先出现了这个几个关键词.

    无法解决的bug

    之前我反复强调,我们看源码,是为了解决问题,而不是简单为了面试装装逼,如果搜索引擎随便搜索第一页都能解决,那还看源码真的是风骚走位完美避开了最高效的解决问题方式

    特定环境出现

    从聊天记录中可以看出,该问题还受到环境的条件限制,不方便模拟,最关键是我还不能直接连上他们公司的环境去帮他看问题.

    望闻问切

    其实很多人写了几年代码之后都常常感叹,写代码真的好容易,就是用各种框架,堆积木式编程.其实他们之所以有这样的感叹,主要是工作中遇到的挑战还不够多.以至于他们认为 原理、 源码这些东西纯粹只是面试装逼.

    当然会看源码解决搜索引擎无法解决问题,还是远远不够的.高并发下.会出现很多难以重现的问题,这个时候,必须要学会一个新的技能,就是通过日志,通过眼神编译, 静态看源码.

    因此,我询问得到了报错日志如下:

    从报错日志中可以看出,这个报错还和 Mybatisplus有关,但是我没用过什么 Mybatisplus啊,这可如何是好?没关系,前面都说了,静态看源码, 眼神编译!,于是我开始新建一个demo,引入相关的依赖.

    九浅一深

    将上图的异常栈再标记一下重点

    从我标记的三个重点加上小学简单的英文就可以看出,在解析 UserPersonalMapper.xml时,没有找到 BaseResultMap.另外一点,从我标记中的重点中也可以看出,这个 BaseResultMap是在另外一个XML,也就是 UserMapper.xml中声明的.

    这个时候可能就有朋友想到,那是不是加载 UserPersonalMapper.xml的时候, UserMapper.xml还没加载导致的呢.导致无法找到 UserMapper.xml定义的 BaseResultMap

    坦白说,这个猜测,一点毛病都没有,非常合情合理

    但是最关键的是,本地跑是没问题的.那为什么我本地跑的时候,又没有报错,这个你又怎么解释?

    很多朋友都问到我怎么看源码,那么我现在就手把手,根据仅有的线索,九浅一深直入源码.

    日志告诉我们是583行的时候报错的(图中已圈),然后 mapperLocations也很明显,就是我们配置我mapper集合,他就是从这里集合中遍历出每一个mapper来进行解析的.

    那么关键问题来了,我们现在是静态看代码,眼神编译,我们打不了断点,那么这个mappe是什么时候set进去的,set了哪些值呢?为了做到毫不保留向公众号粉丝传输心路历程,我就详细截图一下.

    以下几个技巧完全是 IDEA的使用问题

    1.查看变量在哪里被引用

    2.查看方法在哪里被调用

    终于,让我们找到了核心处理逻辑

    从 resolveMapperLocations和 PathMatchingResourcePatternResolver这两个类名和返回值 Resource[],哪怕是把单词拆开一个一个翻译都大概能猜出,这个是根据配置的 /*.xml这种配置,找到所有的xml资源. Resource[]是数组,数组是有序的,所以这个数组中的元素(mapper)顺序的顺序,就能决定我们前面的猜想是不是正确的.

    验证猜想

    于是我就叫该好友添加上这段日志,验证一下猜想

    然后他把能正常启动的日志和异常的日志发出来,如下

    我们发现,果然如我们所料,这个加载的顺序果然有问题,异常启动的, UserMapper.xml在最后才加载,自然导致遍历的时候最后才解析到这个xml,所以这个xml上定义的 BaseResultMap不能被之前加载的使用

    但是关键问题是,还是没说清楚,为什么本地就没问题.为什么本地跑加载的顺序就OK了呢?

    深入浅出

    现在范围已经很小了,我们从前面的猜想,到验证猜想,已经把目标逐步缩小,现在问题就只剩下一个,只要弄清楚 PathMatchingResourcePatternResolver的逻辑,一切就豁然开朗了

    因为线上环境,都是打成jar依赖启动的.而本地走的是classes,所以他们走的代码分支是不一样的

    深入思考

    其实还有一个猥琐的办法,把 PathMatchingResourcePatternResolver这个类拷贝出来,改个名字.比如 FeichaoPathMatchingResourcePatternResolver.然后打上一些简陋的日志信息,如下图

    然后你本地启动,和jar启动,看日志输出.

    那么,这两个分支究竟有什么区别呢?这个本地代码走的代码分支,有一段很重要的逻辑

    他这里会根据资源文件进行排序,那么到底根据什么规则排序

    相关文章

      网友评论

        本文标题:慌了!本地可以跑的项目,一上线就崩?

        本文链接:https://www.haomeiwen.com/subject/bfvcxctx.html