前两天在项目中遇到个很神奇的问题,想着周末有空的时候给解一下
问题的现象
在IDEA中执行main方法能正常跑通程序</br>
但是打包后,执行jar包会报错,错误信息如下:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
是在调用Mapper方法的时候抛出的异常
![](https://img.haomeiwen.com/i9760751/313a6e6945c3eead.png)
大胆猜测,小心求证
此时心中隐隐有答案,猜测大概率是数据源有问题,为了求证心中所想
我在报错的地方打了个断点,在两种不同的场景下分别进行调试
main调试
查看Mapper对应的数据源信息
![](https://img.haomeiwen.com/i9760751/0b893d486128e2d9.png)
jar包调试
使用调试模式执行jar包,打开命令行执行下面命令
java -Xdebug -Xrunjdwp:transport=dt_socket,address=5000,server=y,suspend=y -jar main.jar
在IDEA中配置端口号
- 添加新的配置 选择Remote JVM Debug
- 填写Host: localhost Port: 5000
- -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5000
![](https://img.haomeiwen.com/i9760751/c3260eaa85e710b1.png)
![](https://img.haomeiwen.com/i9760751/96a0cfd2cf46fd07.png)
经过对比发现,Mapper注入的数据源果真是不一样的!
为什么会不一样呢???
代码都是一样的,配置也一样的,为啥打完jar后执行 注入的数据源就不同!
这时会怀疑是不是打包有问题,然后又解压了jar包去看,发现Mapper文件,数据源配置也都在,那大概可以排除是打包的问题了。
这条路走不通,那就换个思路去查一波
现在是可以定位到Mapper注入的数据源是异常的,那就查一下Mapper在注入这个数据源的时候发生了啥
那么Mapper是什么时候被Spring扫描的呢?
看一下spring-mybatis.xml配置文件发现配置了一个bean MapperScannerConfigurer
这个bean注入了扫描的mapper包位置和注入的数据源信息
![](https://img.haomeiwen.com/i9760751/91ccbe62650ea7a0.png)
![](https://img.haomeiwen.com/i9760751/63799148866a6f5b.png)
MapperScannerConfigurer类说明会从basePackage包开始递归实例化Mapper接口
好,那就先断个点在注入Mapper包(basePackage)的地方,debug看看,
![](https://img.haomeiwen.com/i9760751/e3f8152c29a5ac3f.png)
观察一下前面执行的栈
![](https://img.haomeiwen.com/i9760751/318f868f0d75a206.png)
- 在PostProcessorRegistrationDelegate中调用了invokeBeanFactoryPostProcessors
方法 - 该方法会获取BeanDefinitionRegistryPostProcessor类型的需要实例化的beanName列表
- 而MapperScannerConfigurer刚好继承BeanDefinitionRegistryPostProcessor
- 接着调用beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)去实例化该bean
好了,到了这,真相快大白了,前面的时候我们已经知道Mapper是注入了别的数据源,而项目中的数据源也比较多,那就有可能是别的配置文件里也扫描了该Mapper
然后谁先搜索到该Mapper就会注入该类型的数据源
果不其然,翻了别的配置文件一看,有个basePackage使用了通配符匹配,把该Mapper也扫描了进去!!!
![](https://img.haomeiwen.com/i9760751/1f52668fe884d54d.png)
为了验证是不是这个原因,我把该basePackage改了一下,不要扫描到该Mapper,打包执行,程序跑通了!没想到没想到。
再深入挖一下
问题出现的前提条件
- 项目中有多个spring-xxx.xml配置文件
- 打成jar包,使用java -jar执行
那接着来看看spring扫描配置文件在不同场景下的做法
通过debug后定位到方法org.springframework.core.io.support.PathMatchingResourcePatternResolver#findPathMatchingResources
该方法会返回一个Resource数组,表示扫描的配置文件顺序
![](https://img.haomeiwen.com/i9760751/ca7464b3bad0ecf0.png)
- doFindPathMatchingJarResources: 查找Jar文件里的配置文件
很正常的通过迭代器获取文件
![](https://img.haomeiwen.com/i9760751/53c110bf69345373.png)
- doFindPathMatchingFileResources: 查找文件系统内的配置文件
这里的方法调用链会比较深,最后定位到方法
org.springframework.core.io.support.PathMatchingResourcePatternResolver#doRetrieveMatchingFiles
需要注意的是这里调用了Arrays.sort对文件进行了排序
![](https://img.haomeiwen.com/i9760751/5d5ee9480a9c40fc.png)
![](https://img.haomeiwen.com/i9760751/bc3e70a33d04e666.png)
所以才会有这么戏剧性的bug出现
网友评论