以前本身寫過一個關於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