问题
使用通用Mapper 执行insertList,报错如题,大概意思是:没有找到SpecialProvider默认构造方法,SpecialProvider实例化失败。
原因分析
SpecialProvider实例化时机晚了,应该在通用Mapper初始化加载过程中完成,也就是应该让通用Mapper 去完成SpecialProvider实例化。解决方法也就清楚了,应该在通用Mapper 配置上做修改。
SpecialProvider属于一种MapperTemplate,MapperTemplate没有空的构造函数,即<init>()
,因此,如果只是简单的执行 providerType.newInstance()
,就自然报错了。构造MapperTemplate,注入MapperHelper,应该交给通用Mapper 配置.
MapperTemplate,见名知意,Mapper模板类,真正的实现是通过子类和 MapperHelper来完成。
解决
指定mapper 注册类,让MapperHelper 识别并注册InsertListMapper,通用Mapper 完成SpecialProvider实例化。
mapper:
mappers: [tk.mybatis.mapper.common.special.InsertListMapper, tk.mybatis.mapper.common.Mapper]
网上查到的很多资料,都是要配置 tk.mybatis.spring.annotation.MapperScan,这个好像是2.x 版本的配置,我这边用的是1.x 的版本,因此不适用
实现原理分析
通用Mapper 属于自定义Mapper 的功能增强,执行增强的过程,体现在MapperHelper#registerMapper()
,配置启用的策略如下
public class MapperAutoConfiguration {
@PostConstruct
public void addPageInterceptor() {
// 通用Mapper 功能核心实现类 mapperHelper
MapperHelper mapperHelper = new MapperHelper();
// 如果指定了mappers,则注册继承 mappers接口的bean
if (properties.getMappers().size() > 0) {
for (Class mapper : properties.getMappers()) {
//提前初始化MapperFactoryBean,注册mappedStatements
applicationContext.getBeansOfType(mapper);
mapperHelper.registerMapper(mapper);
}
} else {
// 如果没有指定,则默认注册继承 tk.mybatis.mapper.common.Mapper 接口的bean
applicationContext.getBeansOfType(Mapper.class);
mapperHelper.registerMapper(Mapper.class);
}
// 增强的方法,重新设置SqlSource,即从ProviderSqlSource 设置为DynamicSqlSource
// 从java配置转化为可执行的xml
for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
mapperHelper.processConfiguration(sqlSessionFactory.getConfiguration());
}
}
}