以前本身写过一个关于mybatis-plus多表联查的组件,原理是用到了mybatis-plus扩展的口(sql注入),即继承DefaultSqlInjectorspring
/** * @author chengang */ @Component public class MySqlInjector extends DefaultSqlInjector { @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass) { List<AbstractMethod> methodList = super.getMethodList(mapperClass); methodList.add(new JoinMethod()); return methodList; } }
可是集成到别的项目发现不起做用,很奇怪,batis-plus自带的查询没问题,但就是自定义注入器不行,不该该是初始化的时候从spring容器找吗。。。?sql
因而经过断点跟踪,发现注入器是GlobalConfig 的属性,而且有一个默认值缓存
/** * SQL注入器 */ private ISqlInjector sqlInjector = new DefaultSqlInjector();
显然以前确定赋值过一次,继续往前追踪starter有个MybatisPlusAutoConfiguration里面有个初始化beanmybatis
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Bean @ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { // TODO 使用 MybatisSqlSessionFactoryBean 而不是 SqlSessionFactoryBean MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); factory.setDataSource(dataSource); factory.setVfs(SpringBootVFS.class); if (StringUtils.hasText(this.properties.getConfigLocation())) { factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); } applyConfiguration(factory); if (this.properties.getConfigurationProperties() != null) { factory.setConfigurationProperties(this.properties.getConfigurationProperties()); } if (!ObjectUtils.isEmpty(this.interceptors)) { factory.setPlugins(this.interceptors); } if (this.databaseIdProvider != null) { factory.setDatabaseIdProvider(this.databaseIdProvider); } if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); } if (this.properties.getTypeAliasesSuperType() != null) { factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType()); } if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) { factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); } if (!ObjectUtils.isEmpty(this.typeHandlers)) { factory.setTypeHandlers(this.typeHandlers); } Resource[] mapperLocations = this.properties.resolveMapperLocations(); if (!ObjectUtils.isEmpty(mapperLocations)) { factory.setMapperLocations(mapperLocations); } // TODO 修改源码支持定义 TransactionFactory this.getBeanThen(TransactionFactory.class, factory::setTransactionFactory); // TODO 对源码作了必定的修改(由于源码适配了老旧的mybatis版本,但咱们不须要适配) Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver(); if (!ObjectUtils.isEmpty(this.languageDrivers)) { factory.setScriptingLanguageDrivers(this.languageDrivers); } Optional.ofNullable(defaultLanguageDriver).ifPresent(factory::setDefaultScriptingLanguageDriver); // TODO 自定义枚举包 if (StringUtils.hasLength(this.properties.getTypeEnumsPackage())) { factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage()); } // TODO 此处必为非 NULL GlobalConfig globalConfig = this.properties.getGlobalConfig();//这里是初始化全局缓存的最初开始 // TODO 注入填充器 this.getBeanThen(MetaObjectHandler.class, globalConfig::setMetaObjectHandler); // TODO 注入主键生成器 this.getBeanThen(IKeyGenerator.class, i -> globalConfig.getDbConfig().setKeyGenerator(i));//这里注入自定义的主键生成器 // TODO 注入sql注入器 this.getBeanThen(ISqlInjector.class, globalConfig::setSqlInjector);//这里设置注入器属性,注入自定义注入器就在这里 // TODO 注入ID生成器 this.getBeanThen(IdentifierGenerator.class, globalConfig::setIdentifierGenerator); // TODO 设置 GlobalConfig 到 MybatisSqlSessionFactoryBean factory.setGlobalConfig(globalConfig); return factory.getObject(); }
到这里基本就很明确了,当你使用自定义SqlSessionFactory 的时候,本方法不会执行,也就不会初始化刚开始自定义的sql注入器了,知道这个基本问题就解决了,把集成项目的SqlSessionFactory 去掉,或者加上GlobalConfig初始化这一块的代码。app
最后总结一下集成项目的时候一些bean的初始化要注意一些属性的初始化,否则可能会形成一些未知的问题!ide