spring动态数据源实现(通过包名动态设置数据源)
通过创建数据源扫描类可以创建多数据源,但是每新增一个数据源就要相应的实现,遂想根据包路径自动选择相应的数据源
最终效果:
如设置spring.datasource.one.url = xxx,然后mapper类写在one包下如com.mutool.one.mapper.TestMapper即可
设置默认数据源和可选数据源
@Slf4j @Component public class DynaCachedDataSource extends AbstractRoutingDataSource implements EnvironmentAware { private Environment environment; boolean hasInit = false; String validationQuerySql = "select 1";// 验证连接是否成功的sql public DynaCachedDataSource() { super(); super.setTargetDataSources(new HashMap()); } @Override public void setEnvironment(Environment environment) { this.environment = environment; } @Override public Connection getConnection() throws SQLException { if (!hasInit) { initDateSourceByProperties(); } return super.getConnection(); } /** * 初始化配置 */ private void initDateSourceByProperties() { String driver = environment.getProperty("spring.datasource.driver-class-name"); String url = environment.getProperty("spring.datasource.url"); String username = environment.getProperty("spring.datasource.username"); String password = environment.getProperty("spring.datasource.password"); DruidDataSource defaultDS = new DruidDataSource(); defaultDS.setDriverClassName(driver); defaultDS.setUrl(url); defaultDS.setUsername(username); defaultDS.setPassword(password); defaultDS.setValidationQuery(validationQuerySql); //其他属性自行设置 this.setDefaultTargetDataSource(defaultDS); this.setTargetDataSources(getTargetsMap()); super.afterPropertiesSet(); hasInit = true; } private Map<Object, Object> getTargetsMap() { Map<Object, Object> targets = new HashMap<Object, Object>(); Map<String, Map<String, String>> datasourceGroupMap = getDatasourceConfig(); datasourceGroupMap.forEach((k, v) -> { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(v.get("spring.datasource."+k+".driver-class-name")); dataSource.setUrl(v.get("spring.datasource."+k+".url")); dataSource.setUsername(v.get("spring.datasource."+k+".username")); dataSource.setPassword(v.get("spring.datasource."+k+".password")); dataSource.setValidationQuery(validationQuerySql); //其他属性自行设置 targets.put(k, dataSource); }); return targets; } @Override protected Object determineCurrentLookupKey() { return getDataSource(); } // 线程本地环境 private static final ThreadLocal<String> dataSources = new ThreadLocal<String>(); // 设置数据源 public static void setDataSource(String customerType) { dataSources.set(customerType); } // 获取数据源 public static String getDataSource() { return dataSources.get(); } /** * 从spring配置中获取全部数据源配置 * @return */ private Map<String, Map<String, String>> getDatasourceConfig(){ Map<String, Map<String, String>> datasorceGroupMap = new HashMap<>(); StandardServletEnvironment standardServletEnvironment = (StandardServletEnvironment) environment; Iterator<PropertySource<?>> iterator = standardServletEnvironment.getPropertySources().iterator(); while (iterator.hasNext()) { PropertySource<?> source = iterator.next(); Object o = source.getSource(); if (o instanceof Map) { for (Map.Entry<String, Object> entry : ((Map<String, Object>) o).entrySet()) { String key = entry.getKey(); //判断如果以spring.datasource开始的配置取出 if(!key.startsWith("spring.datasource")){ continue; } String value = standardServletEnvironment.getProperty(key); String datasourceGroup = ReUtil.getGroup1("datasource\\.(.*?)\\.", value); if(StrUtil.isBlank(datasourceGroup)){ datasourceGroup = "default"; } Map<String, String> datasourceConfigMap = datasorceGroupMap.get(datasourceGroup); if(datasourceConfigMap == null){ datasourceConfigMap = new HashMap<>(); datasorceGroupMap.put(datasourceGroup, datasourceConfigMap); } datasourceConfigMap.put(key, value); } } } return datasorceGroupMap; } }
动态选择数据源
@Slf4j @Component @Aspect public class DynaDataSourceInterceptor { @Before("execution(* com.mutool..mapper.*Mapper.*(..))") public void dynamicSetDataSoruce(JoinPoint joinPoint) throws Exception { Object target = joinPoint.getTarget(); Class<?> clazz = target.getClass(); String className = clazz.getName(); if(Proxy.isProxyClass(target.getClass())) { Type[] types = AopUtils.getTargetClass(target).getGenericInterfaces(); className = types[0].getTypeName(); } if(!className.contains(".mapper.")){ log.error("数据源切面拦截解析包路径错误,解析得到类名:{}", className); return; } String pkg = className.substring(0, className.indexOf(".mapper.")); pkg = pkg.substring(pkg.lastIndexOf('.') + 1); if (pkg.equals("mybatis")) { Thread.sleep(1000); } DynaCachedDataSource.setDataSource(pkg); } }