基於Apollo遠端配置中心+MybatisPlus的多資料來源配置元件
阿新 • • 發佈:2020-12-30
技術標籤:日常程式碼java原理java原始碼分析mybatis
只是服務員公司內部架構所開發,只是服務於公司專案的架構,無法通用全部專案,若要通用,則還需要進行通用化改造,本文只是提供一個思路
package com.iskytrip.mybatis.inject.mybatis.dataSource; import com.iskytrip.mybatis.inject.mybatis.dataSource.config.ISkyTripDataSourceConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import(ISkyTripDataSourceConfiguration.class) public class DataSourceAutoConfig { }
package com.iskytrip.mybatis.inject.mybatis.dataSource.config; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; import com.ctrip.framework.apollo.internals.DefaultConfig; import com.ctrip.framework.apollo.spring.config.ConfigPropertySource; import com.ctrip.framework.apollo.spring.config.ConfigPropertySourceFactory; import com.ctrip.framework.apollo.spring.util.SpringInjector; import com.iskytrip.framework.util.db.DBConfigEntity; import com.iskytrip.framework.util.exception.BizServiceException; import com.iskytrip.mybatis.inject.util.CodeUtil; import com.iskytrip.mybatis.inject.util.PropertyUtil; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.stereotype.Repository; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import javax.sql.DataSource; import java.util.*; import java.util.stream.Collectors; public class ISkyTripDataSourceConfiguration implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanFactory) { String dbConfig = PropertyUtil.getValue("db.config"); if (StrUtil.isEmpty(dbConfig)) { return; } List<ConfigPropertySource> configPropertySources = SpringInjector.getInstance(ConfigPropertySourceFactory.class).getAllConfigPropertySources(); if (CollUtil.isEmpty(configPropertySources)) { return; } Collections.sort(configPropertySources, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); Map<String, String> valueMap = new HashMap<>(); for (ConfigPropertySource configPropertySource : configPropertySources) { DefaultConfig defaultConfig = (DefaultConfig) configPropertySource.getSource(); for (String name : defaultConfig.getPropertyNames()) { String value; if (!valueMap.containsKey(name) && StrUtil.isNotEmpty(value = defaultConfig.getProperty(name, ""))) { valueMap.put(name, value); } } } String[] strArr = dbConfig.split(","); for (String str : strArr) { String[] strArr1 = str.split("="); registerDataSourceBean(beanFactory, valueMap.get(strArr1[0]), strArr1[1]); } /*PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); paginationInterceptor.setLimit(-1); paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); beanFactory.registerBeanDefinition("paginationInterceptor", BeanDefinitionBuilder.genericBeanDefinition(paginationInterceptor.getClass()).getBeanDefinition());*/ } private void registerDataSourceBean(BeanDefinitionRegistry beanFactory, String value0, String value1) { try { DataSource dataSource = DbBaseConfig.getDbDataSource(JSON.parseObject(value0, DBConfigEntity.class)); beanFactory.registerBeanDefinition(value1 + "#dataSource", BeanDefinitionBuilder.genericBeanDefinition(dataSource.getClass()).getBeanDefinition()); MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = DbBaseConfig.getMybatisSqlSessionFactoryBean(dataSource, getEntityPath(value1), getMapperPath(value1)); SqlSessionFactory sqlSessionFactory = mybatisSqlSessionFactoryBean.getObject(); registerMybatisSqlSessionFactoryBean(value1, beanFactory, mybatisSqlSessionFactoryBean, getEntityPath(value1), getMapperPath(value1), sqlSessionFactory, dataSource); beanFactory.registerBeanDefinition(value1 + "#dataSourceTransactionManager", BeanDefinitionBuilder.genericBeanDefinition(new DataSourceTransactionManager(dataSource).getClass()).addPropertyValue("dataSource", dataSource).getBeanDefinition()); beanFactory.registerBeanDefinition(value1 + "#sqlSessionTemplate", BeanDefinitionBuilder.genericBeanDefinition(SqlSessionTemplate.class).addConstructorArgValue(sqlSessionFactory).getBeanDefinition()); List<String> basePackages = new ArrayList(); basePackages.addAll(Arrays.stream(new String[]{getDaoPath(value1)}).filter(StringUtils::hasText).collect(Collectors.toList())); beanFactory.registerBeanDefinition(value1 + "#mybatis", BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class).addPropertyValue("sqlSessionTemplateBeanName", value1 + "#sqlSessionTemplate").addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages)).getBeanDefinition()); } catch (Exception e) { throw new BizServiceException(e); } } private String getEntityPath(String value) { return getRealPath("entity", value); } private String getDaoPath(String value) { return getRealPath("mapper", value); } private String getMapperPath(String value) { return "classpath*:mapper/" + CodeUtil.underscoreName(value) + "/*.xml"; } private String getRealPath(String type, String value) { try { ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath("com.iskytrip.**.repository." + type + "." + value) + "/**/*.class"; Resource[] resources = resourcePatternResolver.getResources(pattern); //MetadataReader 的工廠類 MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver); for (Resource resource : resources) { //用於讀取類資訊 MetadataReader reader = readerFactory.getMetadataReader(resource); //掃描到的class Class<?> clazz = Class.forName(reader.getClassMetadata().getClassName()); //判斷是否有指定主解 //判斷是否有指定主解 if (clazz.getAnnotation(TableName.class) != null || clazz.getAnnotation(Repository.class) != null) { return clazz.getName().substring(0, clazz.getName().lastIndexOf("."+value+"."))+"."+value; } } } catch (Exception e) { return StrUtil.EMPTY; } return StrUtil.EMPTY; } private void registerMybatisSqlSessionFactoryBean(String value, BeanDefinitionRegistry beanFactory, MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean, String typeAliasesPackage, String mapperLocations, SqlSessionFactory sqlSessionFactory, DataSource dataSource) throws Exception { beanFactory.registerBeanDefinition(value + "#mybatisSqlSessionFactoryBean", BeanDefinitionBuilder.genericBeanDefinition(mybatisSqlSessionFactoryBean.getClass()). addPropertyValue("dataSource", dataSource). addPropertyValue("configuration", sqlSessionFactory.getConfiguration()). addPropertyValue("sqlSessionFactory", sqlSessionFactory). addPropertyValue("vfs", mybatisSqlSessionFactoryBean.getVfs()). addPropertyValue("typeAliasesPackage", typeAliasesPackage). addPropertyValue("mapperLocations", new PathMatchingResourcePatternResolver().getResources(mapperLocations)) .getBeanDefinition()); } }
package com.iskytrip.mybatis.inject.mybatis.dataSource.config; import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS; import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.core.MybatisXMLLanguageDriver; import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; import com.iskytrip.framework.util.db.DBConfigEntity; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import javax.sql.DataSource; import java.io.IOException; public class DbBaseConfig { /** * * @param dataSource * @param typeAliasesPackage * @param mapperLocations * @return */ public static MybatisSqlSessionFactoryBean getMybatisSqlSessionFactoryBean(DataSource dataSource, String typeAliasesPackage, String mapperLocations) throws IOException { MybatisSqlSessionFactoryBean mybatisPlus = new ISkyTripMybatisSqlSessionFactoryBean(); mybatisPlus.setDataSource(dataSource); mybatisPlus.setVfs(SpringBootVFS.class); MybatisConfiguration mc = new MybatisConfiguration(); mc.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class); mc.setMapUnderscoreToCamelCase(true);// 資料庫和java都是駝峰,就不需要 mybatisPlus.setConfiguration(mc); //設定mapper.xml檔案的路徑 mybatisPlus.setTypeAliasesPackage(typeAliasesPackage); mybatisPlus.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations)); return mybatisPlus; } /** * 獲取資料來源 * @param dbConfigEntity * @return */ public static DataSource getDbDataSource(DBConfigEntity dbConfigEntity) { HikariConfig config = new HikariConfig(); config.setJdbcUrl(dbConfigEntity.getUrl()); //資料來源 config.setUsername(dbConfigEntity.getUserName()); //使用者名稱 config.setPassword(dbConfigEntity.getPassword()); //密碼 config.addDataSourceProperty("cachePrepStmts", "true"); //是否自定義配置,為true時下面兩個引數才生效 config.addDataSourceProperty("prepStmtCacheSize", "250"); //連線池大小預設25,官方推薦250-500 config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); //單條語句最大長度預設256,官方推薦2048 config.addDataSourceProperty("useServerPrepStmts", "true"); //新版本MySQL支援伺服器端準備,開啟能夠得到顯著效能提升 config.addDataSourceProperty("useLocalSessionState", "true"); config.addDataSourceProperty("useLocalTransactionState", "true"); config.addDataSourceProperty("rewriteBatchedStatements", "true"); config.addDataSourceProperty("cacheResultSetMetadata", "true"); config.addDataSourceProperty("cacheServerConfiguration", "true"); config.addDataSourceProperty("elideSetAutoCommits", "true"); config.addDataSourceProperty("maintainTimeStats", "false"); HikariDataSource ds = new HikariDataSource(config); return ds; } }
package com.iskytrip.mybatis.inject.mybatis.dataSource.config;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
public class ISkyTripMybatisSqlSessionFactoryBean extends MybatisSqlSessionFactoryBean {
private SqlSessionFactory sqlSessionFactory;
public SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public SqlSessionFactory buildSqlSessionFactory() throws Exception {
if (this.sqlSessionFactory == null) {
this.sqlSessionFactory = super.buildSqlSessionFactory();
}
return this.sqlSessionFactory;
}
}
配置的時候只要在專案的配置檔案里加上這個配置就好,第一個紅框裡的是applo裡的配置,第二個是專案工程裡的package名稱,多個數據源用,隔開