├── README.md └── mybatis-plus-sharding-spring-boot-starter ├── mybatis-plus-sharding-spring-boot-starter.iml ├── pom.xml └── src └── main ├── java └── com │ └── kaikai │ └── starter │ ├── KaiShardingMybatisPlusAutoConfiguration.java │ ├── KaiShardingOneMybatisPlusAutoConfiguration.java │ ├── MybatisPlusShardingProperties.java │ └── annotation │ └── NoShardingMapper.java └── resources └── META-INF └── spring.factories /README.md: -------------------------------------------------------------------------------- 1 | ## mybatis-plus-sharding-spring-boot-starter 2 | 用于解决sharding-jdbc和mybatis-plus整合时对sharding不支持sql的处理的starter 3 | ### 1. 打包 引入打包后的maven依赖 4 | 5 | ### 2. 需要对不支持sql做处理的mapper 加注解 `@NoShardingMapper` 6 | -------------------------------------------------------------------------------- /mybatis-plus-sharding-spring-boot-starter/mybatis-plus-sharding-spring-boot-starter.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /mybatis-plus-sharding-spring-boot-starter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.1.11.RELEASE 10 | 11 | 12 | com.kaikai.starter 13 | mybatis-plus-sharding-spring-boot-starter 14 | 1.1.1 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter 20 | 21 | 22 | com.baomidou 23 | mybatis-plus-boot-starter 24 | 3.3.1 25 | 26 | 27 | org.apache.shardingsphere 28 | sharding-jdbc-spring-boot-starter 29 | 4.0.0-RC1 30 | 31 | 32 | org.projectlombok 33 | lombok 34 | true 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /mybatis-plus-sharding-spring-boot-starter/src/main/java/com/kaikai/starter/KaiShardingMybatisPlusAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.kaikai.starter; 2 | 3 | import com.baomidou.mybatisplus.autoconfigure.*; 4 | import com.baomidou.mybatisplus.core.MybatisConfiguration; 5 | import com.baomidou.mybatisplus.core.config.GlobalConfig; 6 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; 7 | import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; 8 | import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; 9 | import com.baomidou.mybatisplus.core.injector.ISqlInjector; 10 | import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; 11 | import com.kaikai.starter.annotation.NoShardingMapper; 12 | import org.apache.ibatis.annotations.Mapper; 13 | import org.apache.ibatis.mapping.DatabaseIdProvider; 14 | import org.apache.ibatis.plugin.Interceptor; 15 | import org.apache.ibatis.scripting.LanguageDriver; 16 | import org.apache.ibatis.session.ExecutorType; 17 | import org.apache.ibatis.session.SqlSessionFactory; 18 | import org.apache.ibatis.type.TypeHandler; 19 | import org.apache.shardingsphere.shardingjdbc.jdbc.core.datasource.MasterSlaveDataSource; 20 | import org.apache.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource; 21 | import org.mybatis.spring.SqlSessionFactoryBean; 22 | import org.mybatis.spring.SqlSessionTemplate; 23 | import org.mybatis.spring.mapper.MapperScannerConfigurer; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | import org.springframework.beans.BeanWrapper; 27 | import org.springframework.beans.BeanWrapperImpl; 28 | import org.springframework.beans.factory.BeanFactory; 29 | import org.springframework.beans.factory.BeanFactoryAware; 30 | import org.springframework.beans.factory.InitializingBean; 31 | import org.springframework.beans.factory.ObjectProvider; 32 | import org.springframework.beans.factory.annotation.Qualifier; 33 | import org.springframework.beans.factory.support.BeanDefinitionBuilder; 34 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 35 | import org.springframework.boot.autoconfigure.AutoConfigurationPackages; 36 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 37 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 38 | import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; 39 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 40 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 41 | import org.springframework.context.ApplicationContext; 42 | import org.springframework.context.annotation.*; 43 | import org.springframework.core.io.Resource; 44 | import org.springframework.core.io.ResourceLoader; 45 | import org.springframework.core.type.AnnotationMetadata; 46 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 47 | import org.springframework.transaction.PlatformTransactionManager; 48 | import org.springframework.util.Assert; 49 | import org.springframework.util.CollectionUtils; 50 | import org.springframework.util.ObjectUtils; 51 | import org.springframework.util.StringUtils; 52 | 53 | import javax.sql.DataSource; 54 | import java.util.List; 55 | import java.util.Optional; 56 | import java.util.function.Consumer; 57 | import java.util.stream.Stream; 58 | 59 | /** 60 | * KaiMybatisPlusAutoConfiguration 61 | * 62 | * @author pu 63 | * @date 2021/1/12 64 | * time 9:29 65 | */ 66 | @Configuration 67 | @ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class}) 68 | @ConditionalOnSingleCandidate(DataSource.class) 69 | @EnableConfigurationProperties(MybatisPlusProperties.class) 70 | @AutoConfigureAfter({DataSourceAutoConfiguration.class ,MybatisPlusLanguageDriverAutoConfiguration.class}) 71 | public class KaiShardingMybatisPlusAutoConfiguration implements InitializingBean{ 72 | 73 | 74 | private static final Logger logger = LoggerFactory.getLogger(KaiShardingMybatisPlusAutoConfiguration.class); 75 | 76 | private final MybatisPlusProperties properties; 77 | 78 | private final Interceptor[] interceptors; 79 | 80 | private final TypeHandler[] typeHandlers; 81 | 82 | private final LanguageDriver[] languageDrivers; 83 | 84 | private final ResourceLoader resourceLoader; 85 | 86 | private final DatabaseIdProvider databaseIdProvider; 87 | 88 | private final List configurationCustomizers; 89 | 90 | private final List mybatisPlusPropertiesCustomizers; 91 | 92 | private final ApplicationContext applicationContext; 93 | 94 | 95 | public KaiShardingMybatisPlusAutoConfiguration(@Qualifier("mybatis-plus-com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties") MybatisPlusProperties properties, 96 | ObjectProvider interceptorsProvider, 97 | ObjectProvider typeHandlersProvider, 98 | ObjectProvider languageDriversProvider, 99 | ResourceLoader resourceLoader, 100 | ObjectProvider databaseIdProvider, 101 | ObjectProvider> configurationCustomizersProvider, 102 | ObjectProvider> mybatisPlusPropertiesCustomizerProvider, 103 | ApplicationContext applicationContext) { 104 | this.properties = properties; 105 | this.interceptors = interceptorsProvider.getIfAvailable(); 106 | this.typeHandlers = typeHandlersProvider.getIfAvailable(); 107 | this.languageDrivers = languageDriversProvider.getIfAvailable(); 108 | this.resourceLoader = resourceLoader; 109 | this.databaseIdProvider = databaseIdProvider.getIfAvailable(); 110 | this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable(); 111 | this.mybatisPlusPropertiesCustomizers = mybatisPlusPropertiesCustomizerProvider.getIfAvailable(); 112 | this.applicationContext = applicationContext; 113 | } 114 | 115 | @Override 116 | public void afterPropertiesSet() { 117 | if (!CollectionUtils.isEmpty(mybatisPlusPropertiesCustomizers)) { 118 | mybatisPlusPropertiesCustomizers.forEach(i -> i.customize(properties)); 119 | } 120 | checkConfigFileExists(); 121 | } 122 | 123 | private void checkConfigFileExists() { 124 | if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) { 125 | Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation()); 126 | Assert.state(resource.exists(), 127 | "Cannot find config location: " + resource + " (please add config file or check your Mybatis configuration)"); 128 | } 129 | } 130 | 131 | @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") 132 | @Bean 133 | @Primary 134 | public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { 135 | // TODO 使用 MybatisSqlSessionFactoryBean 而不是 SqlSessionFactoryBean 136 | MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); 137 | factory.setDataSource(dataSource); 138 | factory.setVfs(SpringBootVFS.class); 139 | if (StringUtils.hasText(this.properties.getConfigLocation())) { 140 | factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); 141 | } 142 | applyConfiguration(factory); 143 | if (this.properties.getConfigurationProperties() != null) { 144 | factory.setConfigurationProperties(this.properties.getConfigurationProperties()); 145 | } 146 | if (!ObjectUtils.isEmpty(this.interceptors)) { 147 | factory.setPlugins(this.interceptors); 148 | } 149 | if (this.databaseIdProvider != null) { 150 | factory.setDatabaseIdProvider(this.databaseIdProvider); 151 | } 152 | if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { 153 | factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); 154 | } 155 | if (this.properties.getTypeAliasesSuperType() != null) { 156 | factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType()); 157 | } 158 | if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) { 159 | factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); 160 | } 161 | if (!ObjectUtils.isEmpty(this.typeHandlers)) { 162 | factory.setTypeHandlers(this.typeHandlers); 163 | } 164 | if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) { 165 | factory.setMapperLocations(this.properties.resolveMapperLocations()); 166 | } 167 | 168 | // TODO 对源码做了一定的修改(因为源码适配了老旧的mybatis版本,但我们不需要适配) 169 | Class defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver(); 170 | if (!ObjectUtils.isEmpty(this.languageDrivers)) { 171 | factory.setScriptingLanguageDrivers(this.languageDrivers); 172 | } 173 | Optional.ofNullable(defaultLanguageDriver).ifPresent(factory::setDefaultScriptingLanguageDriver); 174 | 175 | // TODO 自定义枚举包 176 | if (StringUtils.hasLength(this.properties.getTypeEnumsPackage())) { 177 | factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage()); 178 | } 179 | // TODO 此处必为非 NULL 180 | GlobalConfig globalConfig = this.properties.getGlobalConfig(); 181 | // TODO 注入填充器 182 | this.getBeanThen(MetaObjectHandler.class, globalConfig::setMetaObjectHandler); 183 | // TODO 注入主键生成器 184 | this.getBeanThen(IKeyGenerator.class, i -> globalConfig.getDbConfig().setKeyGenerator(i)); 185 | // TODO 注入sql注入器 186 | this.getBeanThen(ISqlInjector.class, globalConfig::setSqlInjector); 187 | // TODO 注入ID生成器 188 | this.getBeanThen(IdentifierGenerator.class, globalConfig::setIdentifierGenerator); 189 | // TODO 设置 GlobalConfig 到 MybatisSqlSessionFactoryBean 190 | factory.setGlobalConfig(globalConfig); 191 | return factory.getObject(); 192 | } 193 | 194 | /** 195 | * 检查spring容器里是否有对应的bean,有则进行消费 196 | * 197 | * @param clazz class 198 | * @param consumer 消费 199 | * @param 泛型 200 | */ 201 | private void getBeanThen(Class clazz, Consumer consumer) { 202 | if (this.applicationContext.getBeanNamesForType(clazz, false, false).length > 0) { 203 | consumer.accept(this.applicationContext.getBean(clazz)); 204 | } 205 | } 206 | 207 | // TODO 入参使用 MybatisSqlSessionFactoryBean 208 | private void applyConfiguration( MybatisSqlSessionFactoryBean factory) { 209 | // TODO 使用 MybatisConfiguration 210 | MybatisConfiguration configuration = this.properties.getConfiguration(); 211 | if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) { 212 | configuration = new MybatisConfiguration(); 213 | } 214 | if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) { 215 | for (ConfigurationCustomizer customizer : this.configurationCustomizers) { 216 | customizer.customize(configuration); 217 | } 218 | } 219 | factory.setConfiguration(configuration); 220 | } 221 | 222 | @Bean 223 | @Primary 224 | public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory")SqlSessionFactory sqlSessionFactory) { 225 | ExecutorType executorType = this.properties.getExecutorType(); 226 | if (executorType != null) { 227 | return new SqlSessionTemplate(sqlSessionFactory, executorType); 228 | } else { 229 | return new SqlSessionTemplate(sqlSessionFactory); 230 | } 231 | } 232 | 233 | @Bean 234 | @Primary 235 | public PlatformTransactionManager transactionManager(DataSource dataSource) { 236 | 237 | return new DataSourceTransactionManager(dataSource); 238 | 239 | } 240 | 241 | /** 242 | * This will just scan the same base package as Spring Boot does. If you want more power, you can explicitly use 243 | * {@link org.mybatis.spring.annotation.MapperScan} but this will get typed mappers working correctly, out-of-the-box, 244 | * similar to using Spring Data JPA repositories. 245 | */ 246 | public static class KaiAutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar { 247 | 248 | private BeanFactory beanFactory; 249 | 250 | @Override 251 | public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 252 | 253 | if (!AutoConfigurationPackages.has(this.beanFactory)) { 254 | logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled."); 255 | return; 256 | } 257 | 258 | logger.debug("Searching for mappers annotated with @Mapper"); 259 | 260 | List packages = AutoConfigurationPackages.get(this.beanFactory); 261 | if (logger.isDebugEnabled()) { 262 | packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg)); 263 | } 264 | 265 | BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); 266 | builder.addPropertyValue("processPropertyPlaceHolders", true); 267 | builder.addPropertyValue("annotationClass", Mapper.class); 268 | builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages)); 269 | builder.addPropertyValue("sqlSessionFactoryBeanName", "sqlSessionFactory"); 270 | BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class); 271 | Stream.of(beanWrapper.getPropertyDescriptors()) 272 | // Need to mybatis-spring 2.0.2+ 273 | .filter(x -> x.getName().equals("lazyInitialization")).findAny() 274 | .ifPresent(x -> builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}")); 275 | registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition()); 276 | } 277 | 278 | @Override 279 | public void setBeanFactory(BeanFactory beanFactory) { 280 | this.beanFactory = beanFactory; 281 | } 282 | } 283 | 284 | /** 285 | * If mapper registering configuration or mapper scanning configuration not present, this configuration allow to scan 286 | * mappers based on the same component-scanning path as Spring Boot itself. 287 | */ 288 | @Configuration 289 | @Import(KaiShardingMybatisPlusAutoConfiguration.KaiAutoConfiguredMapperScannerRegistrar.class) 290 | // @ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class}) 291 | public static class KaiMapperScannerRegistrarNotFoundConfiguration implements InitializingBean { 292 | 293 | @Override 294 | public void afterPropertiesSet() { 295 | logger.debug( 296 | "Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer."); 297 | } 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /mybatis-plus-sharding-spring-boot-starter/src/main/java/com/kaikai/starter/KaiShardingOneMybatisPlusAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.kaikai.starter; 2 | 3 | import com.baomidou.mybatisplus.autoconfigure.*; 4 | import com.baomidou.mybatisplus.core.MybatisConfiguration; 5 | import com.baomidou.mybatisplus.core.config.GlobalConfig; 6 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; 7 | import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; 8 | import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; 9 | import com.baomidou.mybatisplus.core.injector.ISqlInjector; 10 | import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; 11 | import com.kaikai.starter.annotation.NoShardingMapper; 12 | import org.apache.ibatis.mapping.DatabaseIdProvider; 13 | import org.apache.ibatis.mapping.Environment; 14 | import org.apache.ibatis.plugin.Interceptor; 15 | import org.apache.ibatis.scripting.LanguageDriver; 16 | import org.apache.ibatis.session.ExecutorType; 17 | import org.apache.ibatis.session.SqlSessionFactory; 18 | import org.apache.ibatis.type.TypeHandler; 19 | import org.apache.shardingsphere.shardingjdbc.jdbc.core.datasource.MasterSlaveDataSource; 20 | import org.apache.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource; 21 | import org.mybatis.spring.SqlSessionFactoryBean; 22 | import org.mybatis.spring.SqlSessionTemplate; 23 | import org.mybatis.spring.mapper.MapperScannerConfigurer; 24 | import org.mybatis.spring.transaction.SpringManagedTransactionFactory; 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | import org.springframework.beans.BeanWrapper; 28 | import org.springframework.beans.BeanWrapperImpl; 29 | import org.springframework.beans.factory.BeanFactory; 30 | import org.springframework.beans.factory.BeanFactoryAware; 31 | import org.springframework.beans.factory.InitializingBean; 32 | import org.springframework.beans.factory.ObjectProvider; 33 | import org.springframework.beans.factory.annotation.Qualifier; 34 | import org.springframework.beans.factory.support.BeanDefinitionBuilder; 35 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 36 | import org.springframework.boot.autoconfigure.AutoConfigurationPackages; 37 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 38 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 39 | import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; 40 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 41 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 42 | import org.springframework.context.ApplicationContext; 43 | import org.springframework.context.annotation.*; 44 | import org.springframework.core.io.Resource; 45 | import org.springframework.core.io.ResourceLoader; 46 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 47 | import org.springframework.core.type.AnnotationMetadata; 48 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 49 | import org.springframework.transaction.PlatformTransactionManager; 50 | import org.springframework.util.Assert; 51 | import org.springframework.util.CollectionUtils; 52 | import org.springframework.util.ObjectUtils; 53 | import org.springframework.util.StringUtils; 54 | 55 | import javax.sql.DataSource; 56 | import java.util.List; 57 | import java.util.Optional; 58 | import java.util.function.Consumer; 59 | import java.util.stream.Stream; 60 | 61 | /** 62 | * KaiMybatisPlusAutoConfiguration 63 | * 64 | * @author pu 65 | * @date 2021/1/12 66 | * time 9:29 67 | */ 68 | @Configuration 69 | @ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class}) 70 | //@ConditionalOnSingleCandidate(DataSource.class) 71 | @EnableConfigurationProperties(MybatisPlusShardingProperties.class) 72 | @AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisPlusLanguageDriverAutoConfiguration.class}) 73 | public class KaiShardingOneMybatisPlusAutoConfiguration implements InitializingBean{ 74 | 75 | 76 | private static final Logger logger = LoggerFactory.getLogger(KaiShardingOneMybatisPlusAutoConfiguration.class); 77 | 78 | private final MybatisPlusShardingProperties properties; 79 | 80 | private final Interceptor[] interceptors; 81 | 82 | private final TypeHandler[] typeHandlers; 83 | 84 | private final LanguageDriver[] languageDrivers; 85 | 86 | private final ResourceLoader resourceLoader; 87 | 88 | private final DatabaseIdProvider databaseIdProvider; 89 | 90 | private final List configurationCustomizers; 91 | 92 | private final List mybatisPlusPropertiesCustomizers; 93 | 94 | private final ApplicationContext applicationContext; 95 | 96 | 97 | public KaiShardingOneMybatisPlusAutoConfiguration(@Qualifier("mybatis-plus-com.kaikai.starter.MybatisPlusShardingProperties")MybatisPlusShardingProperties properties, 98 | ObjectProvider interceptorsProvider, 99 | ObjectProvider typeHandlersProvider, 100 | ObjectProvider languageDriversProvider, 101 | ResourceLoader resourceLoader, 102 | ObjectProvider databaseIdProvider, 103 | ObjectProvider> configurationCustomizersProvider, 104 | ObjectProvider> mybatisPlusPropertiesCustomizerProvider, 105 | ApplicationContext applicationContext) { 106 | this.properties = properties; 107 | this.interceptors = interceptorsProvider.getIfAvailable(); 108 | this.typeHandlers = typeHandlersProvider.getIfAvailable(); 109 | this.languageDrivers = languageDriversProvider.getIfAvailable(); 110 | this.resourceLoader = resourceLoader; 111 | this.databaseIdProvider = databaseIdProvider.getIfAvailable(); 112 | this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable(); 113 | this.mybatisPlusPropertiesCustomizers = mybatisPlusPropertiesCustomizerProvider.getIfAvailable(); 114 | this.applicationContext = applicationContext; 115 | } 116 | 117 | @Override 118 | public void afterPropertiesSet() { 119 | if (!CollectionUtils.isEmpty(mybatisPlusPropertiesCustomizers)) { 120 | mybatisPlusPropertiesCustomizers.forEach(i -> i.customize(properties)); 121 | } 122 | checkConfigFileExists(); 123 | } 124 | 125 | private void checkConfigFileExists() { 126 | if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) { 127 | Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation()); 128 | Assert.state(resource.exists(), 129 | "Cannot find config location: " + resource + " (please add config file or check your Mybatis configuration)"); 130 | } 131 | } 132 | 133 | @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") 134 | @Bean("shardingOneSqlSessionFactory") 135 | public SqlSessionFactory sqlSessionFactory(DataSource dataSource,IdentifierGenerator generator) throws Exception { 136 | // TODO 使用 MybatisSqlSessionFactoryBean 而不是 SqlSessionFactoryBean 137 | MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); 138 | DataSource dataSourceNow=null; 139 | if(dataSource instanceof ShardingDataSource){ 140 | //分片 141 | dataSourceNow=((ShardingDataSource)dataSource).getDataSourceMap().get("m1"); 142 | }else{ 143 | //读写分离 144 | dataSourceNow=((MasterSlaveDataSource)dataSource).getDataSourceMap().get("m1"); 145 | } 146 | factory.setDataSource(dataSourceNow); 147 | factory.setVfs(SpringBootVFS.class); 148 | if (StringUtils.hasText(this.properties.getConfigLocation())) { 149 | factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); 150 | } 151 | applyConfiguration(factory); 152 | // factory.setConfiguration(new MybatisConfiguration()); 153 | if (this.properties.getConfigurationProperties() != null) { 154 | factory.setConfigurationProperties(this.properties.getConfigurationProperties()); 155 | } 156 | if (!ObjectUtils.isEmpty(this.interceptors)) { 157 | factory.setPlugins(this.interceptors); 158 | } 159 | if (this.databaseIdProvider != null) { 160 | factory.setDatabaseIdProvider(this.databaseIdProvider); 161 | } 162 | if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { 163 | factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); 164 | } 165 | if (this.properties.getTypeAliasesSuperType() != null) { 166 | factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType()); 167 | } 168 | if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) { 169 | factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); 170 | } 171 | if (!ObjectUtils.isEmpty(this.typeHandlers)) { 172 | factory.setTypeHandlers(this.typeHandlers); 173 | } 174 | 175 | if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) { 176 | factory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/noSharding/**/*.xml")); 177 | } 178 | 179 | // TODO 对源码做了一定的修改(因为源码适配了老旧的mybatis版本,但我们不需要适配) 180 | Class defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver(); 181 | if (!ObjectUtils.isEmpty(this.languageDrivers)) { 182 | factory.setScriptingLanguageDrivers(this.languageDrivers); 183 | } 184 | Optional.ofNullable(defaultLanguageDriver).ifPresent(factory::setDefaultScriptingLanguageDriver); 185 | 186 | // TODO 自定义枚举包 187 | if (StringUtils.hasLength(this.properties.getTypeEnumsPackage())) { 188 | factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage()); 189 | } 190 | // TODO 此处必为非 NULL 191 | GlobalConfig globalConfig = this.properties.getGlobalConfig(); 192 | // TODO 注入填充器 193 | this.getBeanThen(MetaObjectHandler.class, globalConfig::setMetaObjectHandler); 194 | // TODO 注入主键生成器 195 | this.getBeanThen(IKeyGenerator.class, i -> globalConfig.getDbConfig().setKeyGenerator(i)); 196 | // TODO 注入sql注入器 197 | this.getBeanThen(ISqlInjector.class, globalConfig::setSqlInjector); 198 | // TODO 注入ID生成器 199 | this.getBeanThen(IdentifierGenerator.class, globalConfig::setIdentifierGenerator); 200 | // TODO 设置 GlobalConfig 到 MybatisSqlSessionFactoryBean 201 | factory.setGlobalConfig(globalConfig); 202 | return factory.getObject(); 203 | } 204 | 205 | /** 206 | * 检查spring容器里是否有对应的bean,有则进行消费 207 | * 208 | * @param clazz class 209 | * @param consumer 消费 210 | * @param 泛型 211 | */ 212 | private void getBeanThen(Class clazz, Consumer consumer) { 213 | if (this.applicationContext.getBeanNamesForType(clazz, false, false).length > 0) { 214 | consumer.accept(this.applicationContext.getBean(clazz)); 215 | } 216 | } 217 | 218 | // TODO 入参使用 MybatisSqlSessionFactoryBean 219 | private void applyConfiguration(MybatisSqlSessionFactoryBean factory) { 220 | // TODO 使用 MybatisConfiguration 221 | MybatisConfiguration configuration = this.properties.getConfiguration(); 222 | 223 | if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) { 224 | configuration = new MybatisConfiguration(); 225 | } 226 | if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) { 227 | for (ConfigurationCustomizer customizer : this.configurationCustomizers) { 228 | customizer.customize(configuration); 229 | } 230 | } 231 | System.out.println("noSharing ------- init"); 232 | factory.setConfiguration(configuration); 233 | } 234 | 235 | @Bean("shardingOneSqlSessionTemplate") 236 | public SqlSessionTemplate sqlSessionTemplate(@Qualifier("shardingOneSqlSessionFactory") SqlSessionFactory sqlSessionFactory) { 237 | ExecutorType executorType = this.properties.getExecutorType(); 238 | if (executorType != null) { 239 | return new SqlSessionTemplate(sqlSessionFactory, executorType); 240 | } else { 241 | return new SqlSessionTemplate(sqlSessionFactory); 242 | } 243 | } 244 | 245 | 246 | 247 | @Bean("noShardingTransactionManager") 248 | public PlatformTransactionManager transactionManager(DataSource dataSource) { 249 | if(dataSource instanceof ShardingDataSource){ 250 | return new DataSourceTransactionManager(((ShardingDataSource)dataSource).getDataSourceMap().get("m1")); 251 | }else{ 252 | return new DataSourceTransactionManager(((MasterSlaveDataSource)dataSource).getDataSourceMap().get("m1")); 253 | } 254 | } 255 | 256 | /** 257 | * This will just scan the same base package as Spring Boot does. If you want more power, you can explicitly use 258 | * {@link org.mybatis.spring.annotation.MapperScan} but this will get typed mappers working correctly, out-of-the-box, 259 | * similar to using Spring Data JPA repositories. 260 | */ 261 | public static class KaiShardingOneAutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar { 262 | 263 | private BeanFactory beanFactory; 264 | 265 | @Override 266 | public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 267 | 268 | if (!AutoConfigurationPackages.has(this.beanFactory)) { 269 | logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled."); 270 | return; 271 | } 272 | 273 | logger.debug("Searching for mappers annotated with @Mapper"); 274 | 275 | List packages = AutoConfigurationPackages.get(this.beanFactory); 276 | if (logger.isDebugEnabled()) { 277 | packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg)); 278 | } 279 | 280 | BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); 281 | builder.addPropertyValue("processPropertyPlaceHolders", true); 282 | builder.addPropertyValue("annotationClass", NoShardingMapper.class); 283 | String basePackage = StringUtils.collectionToCommaDelimitedString(packages); 284 | builder.addPropertyValue("basePackage", basePackage); 285 | builder.addPropertyValue("sqlSessionFactoryBeanName", "shardingOneSqlSessionFactory"); 286 | BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class); 287 | Stream.of(beanWrapper.getPropertyDescriptors()) 288 | // Need to mybatis-spring 2.0.2+ 289 | .filter(x -> x.getName().equals("lazyInitialization")).findAny() 290 | .ifPresent(x -> builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}")); 291 | registry.registerBeanDefinition("shardingOneMapperScannerConfigurer", builder.getBeanDefinition()); 292 | } 293 | 294 | @Override 295 | public void setBeanFactory(BeanFactory beanFactory) { 296 | this.beanFactory = beanFactory; 297 | } 298 | } 299 | 300 | /** 301 | * If mapper registering configuration or mapper scanning configuration not present, this configuration allow to scan 302 | * mappers based on the same component-scanning path as Spring Boot itself. 303 | */ 304 | @Configuration 305 | @Import(KaiShardingOneMybatisPlusAutoConfiguration.KaiShardingOneAutoConfiguredMapperScannerRegistrar.class) 306 | // @ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class}) 307 | public static class KaiShardingOneMapperScannerRegistrarNotFoundConfiguration implements InitializingBean { 308 | 309 | @Override 310 | public void afterPropertiesSet() { 311 | logger.debug( 312 | "Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer."); 313 | } 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /mybatis-plus-sharding-spring-boot-starter/src/main/java/com/kaikai/starter/MybatisPlusShardingProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2020, baomidou (jobob@qq.com). 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | *

8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package com.kaikai.starter; 17 | 18 | import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties; 19 | import com.baomidou.mybatisplus.core.MybatisConfiguration; 20 | import com.baomidou.mybatisplus.core.config.GlobalConfig; 21 | import com.baomidou.mybatisplus.core.toolkit.Constants; 22 | import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils; 23 | import lombok.Data; 24 | import lombok.experimental.Accessors; 25 | import org.apache.ibatis.scripting.LanguageDriver; 26 | import org.apache.ibatis.session.ExecutorType; 27 | import org.springframework.boot.context.properties.ConfigurationProperties; 28 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 29 | import org.springframework.core.io.Resource; 30 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 31 | import org.springframework.core.io.support.ResourcePatternResolver; 32 | 33 | import java.io.IOException; 34 | import java.util.Optional; 35 | import java.util.Properties; 36 | import java.util.stream.Stream; 37 | 38 | /** 39 | * Configuration properties for MyBatis. 40 | * 41 | * @author Eddú Meléndez 42 | * @author Kazuki Shimizu 43 | */ 44 | @Data 45 | @Accessors(chain = true) 46 | @ConfigurationProperties(prefix = Constants.MYBATIS_PLUS) 47 | public class MybatisPlusShardingProperties extends MybatisPlusProperties { 48 | 49 | private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); 50 | 51 | /** 52 | * Location of MyBatis xml config file. 53 | */ 54 | private String configLocation; 55 | 56 | /** 57 | * Locations of MyBatis mapper files. 58 | * 59 | * @since 3.1.2 add default value 60 | */ 61 | private String[] mapperLocations = new String[]{"classpath*:/noSharding/**/*.xml"}; 62 | 63 | /** 64 | * Packages to search type aliases. (Package delimiters are ",; \t\n") 65 | */ 66 | private String typeAliasesPackage; 67 | 68 | /** 69 | * The super class for filtering type alias. 70 | * If this not specifies, the MyBatis deal as type alias all classes that searched from typeAliasesPackage. 71 | */ 72 | private Class typeAliasesSuperType; 73 | 74 | /** 75 | * Packages to search for type handlers. (Package delimiters are ",; \t\n") 76 | */ 77 | private String typeHandlersPackage; 78 | 79 | /** 80 | * Indicates whether perform presence check of the MyBatis xml config file. 81 | */ 82 | private boolean checkConfigLocation = false; 83 | 84 | /** 85 | * Execution mode for {@link org.mybatis.spring.SqlSessionTemplate}. 86 | */ 87 | private ExecutorType executorType; 88 | 89 | /** 90 | * The default scripting language driver class. (Available when use together with mybatis-spring 2.0.2+) 91 | *

92 | * 如果设置了这个,你会至少失去几乎所有 mp 提供的功能 93 | */ 94 | private Class defaultScriptingLanguageDriver; 95 | 96 | /** 97 | * Externalized properties for MyBatis configuration. 98 | */ 99 | private Properties configurationProperties; 100 | 101 | /** 102 | * A Configuration object for customize default settings. If {@link #configLocation} 103 | * is specified, this property is not used. 104 | * TODO 使用 MybatisConfiguration 105 | */ 106 | @NestedConfigurationProperty 107 | private MybatisConfiguration configuration; 108 | 109 | /** 110 | * TODO 枚举包扫描 111 | */ 112 | private String typeEnumsPackage; 113 | 114 | /** 115 | * TODO 全局配置 116 | */ 117 | @NestedConfigurationProperty 118 | private GlobalConfig globalConfig = GlobalConfigUtils.defaults(); 119 | 120 | 121 | @Override 122 | public Resource[] resolveMapperLocations() { 123 | return Stream.of(Optional.ofNullable(this.mapperLocations).orElse(new String[0])) 124 | .flatMap(location -> Stream.of(getResources(location))) 125 | .toArray(Resource[]::new); 126 | } 127 | 128 | private Resource[] getResources(String location) { 129 | try { 130 | return resourceResolver.getResources(location); 131 | } catch (IOException e) { 132 | return new Resource[0]; 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /mybatis-plus-sharding-spring-boot-starter/src/main/java/com/kaikai/starter/annotation/NoShardingMapper.java: -------------------------------------------------------------------------------- 1 | package com.kaikai.starter.annotation; 2 | 3 | import org.springframework.context.annotation.Lazy; 4 | import org.springframework.stereotype.Component; 5 | 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | /** 12 | * M1Dao 13 | * 14 | * @author pu 15 | * @date 2021/1/11 16 | * time 12:19 17 | */ 18 | @Retention(RetentionPolicy.RUNTIME) 19 | @Target(ElementType.TYPE) 20 | @Component 21 | @Lazy 22 | public @interface NoShardingMapper { 23 | 24 | String value() default ""; 25 | } 26 | -------------------------------------------------------------------------------- /mybatis-plus-sharding-spring-boot-starter/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | com.kaikai.starter.KaiShardingMybatisPlusAutoConfiguration,\ 3 | com.kaikai.starter.KaiShardingOneMybatisPlusAutoConfiguration 4 | 5 | 6 | --------------------------------------------------------------------------------