一、问题现象
开发时遇到一个问题,tomcat启动的时候,加载到 dataSource 时即停住,但是并不抛出异常。 根据以往经验这是mybatis的xml文件里有错误内容,但是具体位置和错误原因不得而知。一般来说简单的错误肉眼就可以找出来,但是这次肉眼检查后很难找出问题原因。
所以现在急需一种方式能够获得具体的异常信息进行调试。
二、问题原因
通过检查mybatis的bean加载工厂类SqlSessionFactoryBean之后发现,mybatis在循环加载xml配置文件时,遇到加载错误会抛出一个 NestedIOException异常,但是并不会打印出错误堆栈信息。
具体异常处理方式见下方第三张图红框部分,代码如下:
-----------------省略中间部分代码--------------------
-----------------省略中间部分代码--------------------
三、解决方案
1、 既然加载xml文件方法没有打印日志信息,那么我们自定义一个工厂类继承SqlSessionFactoryBean,然后重写buildSqlSessionFactory方法打出错误信息即可。
重写方法中,直接执行父类的buildSqlSessionFactory方法,然后捕获异常(之前说到此方法会抛出NestedIOException异常),最后加上原先的finally方法。
具体代码如下:
2、创建自定义工厂类后,再修改配置文件,将原先的 SqlSessionFactoryBean(下图注释部分) 替换为新的 BeanFactoryByMybatisDebug(下图新增部分)
3、 配置完成之后启动 tomcat,发现系统打印出以下异常:
4、异常显示,下图中自定义的映射类无法找到,但是该类确实存在而且路径拼写正确,如下图:
5、 检查该类之后发现有一个不同的地方,那就是该类属于内部类。所以怀疑mybatis无法找到该类应该是内部类引起的。
------------------省略中间部分代码---------------------
6、尝试迁移该内部类,创建一个相同内容的类。再次启动tomcat测试,发现系统正常运行,mybatis加载成功,此次问题就出现在内部类上面。
四、深入分析
1、mybatis 通过TypeHandleRegistry 类将SQL查询结果映射成xml文件中配置的类的对象。 2、映射操作时,首先要定位到具体的类或者包。利用java的反射机制就可以知道这个类的class属性。 3、查看具体注册包的函数时发现,代码使用了几个条件对类的class属性做出了限制, 分别为:内部类、接口、抽象类、package_info类。这几种类型的类不进行注册!那么造成 ClassNotFoundException 异常就理所当然了!
------------------省略中间部分代码--------------------