1.创建DynamicDataSource并继承AbstractRoutingDataSource,实现determineCurrentLookupKey方法 public final class DynamicDataSource extends AbstractRoutingDataSource implements ApplicationContextAware {
? ? private static final String DATA_SOURCES_NAME = "targetDataSources";
? ? private ApplicationContext applicationContext;
? ? @Override ? ? protected Object determineCurrentLookupKey() { ? ? ? ? DataSourceBeanBuilder dataSourceBeanBuilder = DataSourceHolder.getDataSource(); ? ? ? ? if (dataSourceBeanBuilder == null) { ? ? ? ? ? ? return null; ? ? ? ? } ? ? ? ? DataSourceBean dataSourceBean = new DataSourceBean(dataSourceBeanBuilder); ? ? ? ? try { ? ? ? ? ? ? Map<Object, Object> map = null; ? ? ? ? ? ? map = getTargetDataSources();
? ? ? ? ? ? synchronized (map) { ? ? ? ? ? ? ? ? if (!map.containsKey(dataSourceBean.getBeanName())) { ? ? ? ? ? ? ? ? ? ? map.put(dataSourceBean.getBeanName(), createDataSource(dataSourceBean)); ? ? ? ? ? ? ? ? ? ? super.afterPropertiesSet();//通知spring有bean更新 ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } catch (NoSuchFieldException e) { ? ? ? ? ? ? logger.info("failed:" + e); ? ? ? ? } catch (IllegalAccessException e) { ? ? ? ? ? ? logger.info("failed:" + e); ? ? ? ? } ? ? ? ? return dataSourceBean.getBeanName();
? ? }
? ? private Object createDataSource(DataSourceBean dataSourceBean) throws IllegalAccessException { ? ? ? ? //在spring容器中创建并且声明bean ? ? ? ? ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext; ? ? ? ? DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory(); ? ? ? ? BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(DruidDataSource.class); ? ? ? ? //将dataSourceBean中的属性值赋给目标bean ? ? ? ? Map<String, Object> properties = getPropertyKeyValues(DataSourceBean.class, dataSourceBean); ? ? ? ? for (Map.Entry<String, Object> entry : properties.entrySet()) { ? ? ? ? ? ? beanDefinitionBuilder.addPropertyValue((String) entry.getKey(), entry.getValue()); ? ? ? ? } ? ? ? ? beanFactory.registerBeanDefinition(dataSourceBean.getBeanName(), beanDefinitionBuilder.getBeanDefinition()); ? ? ? ? return applicationContext.getBean(dataSourceBean.getBeanName()); ? ? }
? ? private Map<Object, Object> getTargetDataSources() throws NoSuchFieldException, IllegalAccessException { ? ? ? ? Field field = AbstractRoutingDataSource.class.getDeclaredField(DATA_SOURCES_NAME); ? ? ? ? field.setAccessible(true); ? ? ? ? return (Map<Object, Object>) field.get(this); ? ? }
? ? private <T> Map<String, Object> getPropertyKeyValues(Class<T> clazz, Object object) throws IllegalAccessException { ? ? ? ? Field[] fields = clazz.getDeclaredFields(); ? ? ? ? Map<String, Object> result = new HashMap<String, Object>(); ? ? ? ? for (Field field : fields) { ? ? ? ? ? ? field.setAccessible(true); ? ? ? ? ? ? result.put(field.getName(), field.get(object)); ? ? ? ? } ? ? ? ? result.remove("beanName"); ? ? ? ? return result; ? ? }
? ? @Override ? ? public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { ? ? ? ? this.applicationContext=applicationContext; ? ? } } 2.threadLocal保存数据库连接信息表,保证线程安全
public final class DataSourceHolder { ? ? private static ThreadLocal<DataSourceBeanBuilder> threadLocal=new ThreadLocal<DataSourceBeanBuilder>(){ ? ? ? ? @Override ? ? ? ? protected DataSourceBeanBuilder initialValue() { ? ? ? ? ? ? return null; ? ? ? ? } ? ? };
? ? static DataSourceBeanBuilder getDataSource(){ ? ? ? ? return threadLocal.get(); ? ? }
? ? public static void setDataSource(DataSourceBeanBuilder dataSourceBeanBuilder){ ? ? ? ? threadLocal.set(dataSourceBeanBuilder); ? ? }
? ? public static void clearDataSource(){ ? ? ? ? threadLocal.remove(); ? ? } } 3.设置数据源上下文环境工具类 public class DataSourceContext {
? ? public static void setDataSource(DataSourceBeanBuilder dataSourceBeanBuilder) { ? ? ? ? DataSourceHolder.setDataSource(dataSourceBeanBuilder); ? ? }
? ? public static void clearDataSource() { ? ? ? ? DataSourceHolder.clearDataSource(); ? ? } } 4.测试 public List<Object> exectQuery4LimitQuery(DataSourceBeanBuilder dataSourceBeanBuilder, String resourceSql, long limitCount, long offset, String queryConditions, String path) { ? ? ? ? List<Object> queryResults = new ArrayList<>(); ? ? ? ? DataSourceContext.setDataSource(dataSourceBeanBuilder); ? ? ? ? try { ? ? ? ? ? ? //region 查询数据 ? ? ? ? ? ? ? ? ? ? ? ? //endregion 时间格式字段处理完毕 ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? logger.error(String.format("url %s query sql error for %s", resourceSql, e)); ? ? ? ? ? ? throw new RuntimeException("querying database error"); ? ? ? ? } finally { ? ? ? ? ? ? DataSourceContext.clearDataSource(); ? ? ? ? } ? ? ? ? return queryResults; ? ? } ?
|