通用mapper
通用mapper是mybatis的扩展,它提供了一系列的通用方法,避免了冗余的xml编写和公共增删改查的重复劳动。它极大的简化了单表的增删改查,并可以随意的按照自己的需要选择通用方法,还可以很方便的开发自己的通用方法。
本人曾使用spring整合通用mapper一直未出现问题,后来项目升级为spring boot,在整合通用mapper时出现了一个问题,我也曾在github上询问(issues)作者,但作者也未提供好的解决方案。报错如下(截取了一段):
Caused by: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method (tk.mybatis.mapper.provider.base.BaseSelectProvider.dynamicSQL). Cause: java.lang.InstantiationException: tk.mybatis.mapper.provider.base.BaseSelectProvider
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77) ~[mybatis-spring-1.3.1.jar:1.3.1]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446) ~[mybatis-spring-1.3.1.jar:1.3.1]
at com.sun.proxy.$Proxy81.selectList(Unknown Source) ~[?:?]
at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:230) ~[mybatis-spring-1.3.1.jar:1.3.1]
at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:137) ~[mybatis-3.4.4.jar:3.4.4]
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:75) ~[mybatis-3.4.4.jar:3.4.4]
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59) ~[mybatis-3.4.4.jar:3.4.4]
at com.sun.proxy.$Proxy82.selectAll(Unknown Source) ~[?:?]
Caused by: org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method (tk.mybatis.mapper.provider.base.BaseSelectProvider.dynamicSQL). Cause: java.lang.InstantiationException: tk.mybatis.mapper.provider.base.BaseSelectProvider
at org.apache.ibatis.builder.annotation.ProviderSqlSource.createSqlSource(ProviderSqlSource.java:103) ~[mybatis-3.4.4.jar:3.4.4]
at org.apache.ibatis.builder.annotation.ProviderSqlSource.getBoundSql(ProviderSqlSource.java:73) ~[mybatis-3.4.4.jar:3.4.4]
at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:292) ~[mybatis-3.4.4.jar:3.4.4]
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:81) ~[mybatis-3.4.4.jar:3.4.4]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148) ~[mybatis-3.4.4.jar:3.4.4]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141) ~[mybatis-3.4.4.jar:3.4.4]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_111]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_111]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_111]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_111]
作者说这个问题是由于通用mapper没有初始化引起的,我查阅了关于spring boot中Configuration和AutoConfiguration加载顺序的资料,得出问题原因:spring boot中Configuration的加载在AutoConfiguration之前。
but, 为什么mybatis的starter初始化没有问题?
github上的一篇文章解答了这个问题(但我目前没在spring官网找到该描述的出处,如您找到了,请告知,谢谢。)
我翻看了作者实现starter的源码,发现作者是使用 @PostConstruct 完成通用mapper的初始化的,所以在 Configuration 之后才会初始化,这就引发了以上的错误。
弄明白了问题所在,那该怎么解决呢?
弄明白原因了,其实问题就解决了,我们只要让通用mapper的AutoConfiguration在Configuration之前加载就可以了,但我们没办法在使用作者提供的starter,需要自己来实现。我将实现后的代码放到了github
后来我有翻看了作者的另一个关于mybatis开源项目PageHelper,发现它的starter也是通过 @PostConstruct 实现,所以它也会有上面描述的问题,我把它的starter也修改了,放到了github