事件背景
同事反馈,相同的jar包,在多人本地的电脑、多台服务器中,都是可以正常启动的,只有在其中一台服务器,简称它为A,无法启动,因为启动后的初始化操作中有一个调用mybatis方法的操作,
但是调用该方法后,出现 Invalid bound statement (not found): xxxxx
,说这个方法没有绑定上的错误。
调查
去观察了一下代码的配置: mapper-locations: classpath*:com/cm/qrpmp/**/xml/*.xml
好像也并没有什么不对的地方,再加上我自己的电脑本地验证了一下,依然可以正常启动,
于是想着远程debug一下A服务器上不行的时候的堆栈情况,开启远程debug模式
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar YourApp.jar
来到这个位置后,观察了一下当时的 configuration 情况,发现其中的mapper映射确实没有我们想要的,于是观察了一下当时的mapper方法扫描的数量,大概是1145个,
随后我们在本地也启动了调试,在这个位置,发现扫描出来的mapper方法是1445个,多了300个,也就是说服务器上并没有扫描到和本地一样的方法数量,奇怪的是其他服务器是可以的,
这个过程中我们检查了打包后的配置文件、以及xml文件有没有被打包进去,发现都是正确的,
继续追踪
于是想看一下mybatis plus在扫描我们指定的路径过程中发生了什么,
这里追踪到了MyBatisSqlSessionFactoryBean的buildSqlSessionFactory方法这里,在这里发现 mapperLocations 是一个空的对象,说明这里并没有被注入,
于是再向上追踪一下这个对象从什么地方注入的,发现他在 MybatisPlusAutoConfiguration中的 sqlSessionFactory 方法这里进行注入,
其来源自 MybatisPlusProperties 中的 resolveMapperLocations 方法,
于是再这里打了断点调试后,真相即将出现了,在A这台服务器上这里出现的路径竟然不是我们配置中写的,而是另一个毫不相干的,
所以问题出现了在哪里?因为这个错误的配置是另一个jar中的,一度怀疑是不是云服务器出现了缓存啥的读取信息错误。。。
于是换个路径启动,发现正常了。。。。 回到原本的路径就不行,再细看这个路径下有一个config目录。。。。 config目录里有spring boot的 yaml 配置文件,而这个配置文件中的路径就是刚刚debug出错误的路径。。。。
把这个文件删除后,启动又正常了。。。 所以瞬间怀疑,spring boot 默认读取了这个文件中的配置?
解决
在本地验证了一下发现确实如此,如果jar的同目录中存在一个config目录,里面有yaml文件的话 spring boot默认会读这个,所以出现了这个乌龙,
spring boot的读取顺序:https://blog.csdn.net/qq_52139871/article/details/124872875
所以最终其实是spring boot对yaml文件读取顺序导致的问题,我们一直以为它会读jar包中的,没想到这个config目录 近水楼台先得月了。
PS(其他服务器可以,是因为他在其他服务器启动的时候又手动指定了spring.config.location,A这台直接用了java -jar 没指定,所以默认读了当前的config下。。。)总之,各方面的原因导致了问题的出现,这里又验证了多了解源码实现也是有好处的,掌控你所使用的东西