因为软连接导致mybatis无法正常启动
最近接手的一个项目,投产上线,遇到很多问题,其中一个问题比较有意思,记录一下。
背景
简单说下背景,我们的应用是SpringBoot+Mybatis,通过内部CI工具部署不同环境,在dev、stg、uat环境都没问题,投产时启动报错,错误日志如下:
1 | Caused by: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.yicallv1.dao.AgentSkillMapper.create. please check URL [jar:file:/export/package/iim-thirdparty-prod-20211112T123635026/lib/iim-thirdparty-1.0.1.jar!/BOOT-INF/classes!/sqlmap/AgentSkillMapper.xml] and URL [jar:file:/export/server/iim-thirdparty/lib/iim-thirdparty-1.0.1.jar!/BOOT-INF/classes/sqlmap/AgentSkillMapper.xml] |
排查
刚开始看这个问题有点懵,先后检查mapper文件名、生产jar包反编译、生产主机操作系统版本、环境等,都没有问题。后来仔细看了下报错,提示/export/package/iim-thirdparty-prod-20211112T123635026/lib/iim-thirdparty-1.0.1.jar!/BOOT-INF/classes!/sqlmap/AgentSkillMapper.xml
与
/export/server/iim-thirdparty/lib/iim-thirdparty-1.0.1.jar!/BOOT-INF/classes/sqlmap/AgentSkillMapper.xml
文件重名。跟运维沟通,发现生产环境与其他环境不一致,会对jar包所在目录简历一个软连接。包实际路径为上面的路径,软连接路径为下面的路径,为了统一生产启动脚本,脚本中启动jar包的命令,都是使用软连接路径。
到这里,可以分析出来,mybatis在服务启动扫描mapper文件时,应该是将真实路径、软连接路径都扫了一遍,所以所有的mapper文件才会提示有重名。
再进一步分析代码,加载mapper文件的配置,代码如下:
bean.setMapperLocations(resolver.getResources("classpath*:**/sqlmap/*.xml"));
问题应该出在classpath*
上,mybatis会遍历所有的classpath,其中包括了真实路径、软连接路径。至此,找到原因,并最终修改为如下:
bean.setMapperLocations(resolver.getResources("classpath:sqlmap/*.xml"));