记一次使用IDEA整合springboot与mybatis的填坑
起因:来新公司3个月了,公司平台用的框架是springboot+mybatis+dubbo,开发工具是IDEA,接触了3个月,觉得已经掌握的很熟练了,个人对springboot和mybatis的印象都是学习成本极低,好上手。最近在网上下载了套springboot整合shiro与mybatis实现权限认证功能的教学视频,视频里老师使用的IDE是Eclipse。视频很短,50分钟学完,当时觉得自己用IDEA写套权限认证的demo也就30分钟吧,也没什么技术难点,说干就干,结果分分钟被打脸,整合mybatis就报错了,如图:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.luokui.demo.mapper.UserMapper.findByName
什么鬼,绑定异常:无效的绑定声明,按照平时的开发习惯不可能报这个错。。。。。。。
工程路径没问题啊!!!
百度,Google了半天一点收获也没有,基本都是检查包扫描啊,映射文件之类的,根本不是引起错误的原因。对比了下视频中的代码,和我自己的代码,规范一致,为什么人家不报错,自己的报错了,WTF…
不解决掉这个问题总有一种抓心挠肝的感觉,网上并没有找到什么解决方案,只能静下心来自己思考,只剩一条路了,那就是去Debug mybatis源码。说来惭愧,每天都用着mybatis,确重来没有思考过它是如何实现的,这种不求甚解习惯也是这次趟坑的原因之一吧。
这里简单说下mybatis实现原理,不作为本篇文章重点。众所周知,这种ORM框架都封装了原生的jdbc,mybatis写个dao接口,然后写个XXXMapper.xml映射文件,就可以实现对数据库的CRUD操作了。其实主要是基于java的动态代理,生成一个mapper代理类,通过解析xml文件,动态的创建SqlSessionFactory,SqlSession Executor,StatementHandler,ParameterHandler,ResultHandler和TypeHandler等几个处理器 ,然后在spring容器中生成bean。
分析源码查找问题原因
基于报错提示,很明显,定位到MapperMethod类的内部类SqlCommand方法
断点打上去,一步步跟,简单解释下代码,就是从一个map根据相应的key取出对应的value,现在这个value为空,value的类型是MappedStatement,其中封装了些CRUD方法的相关属性,比如方法名,sql语句,参数类型,返回类型等等,现在这个MappedStatement的引用是null,所以抛出了BindingException,显而易见,找到将XXXMapper.xml封装成MappedStatement的过程将成为本次解决问题的重点。
项目启动的时候因为配置了包扫描所以自动会把XXXMapper.xml文件中的内容通过MapperRegistry类的addMapper方法解析成mapper代理类的相关属性。
断点跟到loadXmlResource()方法,xml文件加载都是在这里处理的。
断点跟到getResourceAsStream方法
发现返回的io流是null,等等不是抛IO异常了吗,为什么日志里看不到,查看上个方法,原来把异常捕获了,但没做处理,很坑爹有木有,如果这段代码是我们身边的同事写的,可能直接就破口大骂了,但既然是mybatis的源码,或许出于其他方面的原因考虑,这里没有打日志,不明觉厉有木有。
这里为什么用for循环来加载xml文件路径生成io流,简单提醒句,如果了解jvm的双亲委派模型很好理解这段代码,不了解的同学自行百度下,不是本文重点,不做过多阐述。
那么问题已经很明显了,根据包扫描提供的路径加载不到配置文件,路径没有错,又是为什么呢?
原来IDEA不会编译src的java目录下的xml文件,第一次接触感觉很坑爹有木有,怪不得视频教程中的老师使用Eclipse 。解决方案如下:
在pom文件中加入resources配置路径,重新test,大功告成。
小结
编程之路切记不要眼高手低,脚踏实地才能走的更远,共勉之。