1.新建DynamicDataSource.java内容如下:
package com.immo.ssm.common;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 配置多个数据源与切换数据源的方法
*
* @author LinHai Tan
*
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
/**
* 内置对象
*/
private static DynamicDataSource obj = new DynamicDataSource();
/**
* 保存所有dataSources的map
*/
private static Map<Object, Object> dataSourceMap = new HashMap<>();
/**
* 用于保存需要使用数据源的key的变量
*/
private static ThreadLocal<String> dataSources = new ThreadLocal<String>();
/**
* 此类对象不需要有多个,私有构造方法
*/
private DynamicDataSource() {
}
/**
* 设置需要使用的数据源的key
*
* @param dataSource
*/
public static void setDataSources(String dataSource) {
dataSources.set(dataSource);
}
/**
* 获得需要使用的数据源的key
*
* @return
*/
public static String getDataSources() {
return dataSources.get();
}
/**
* 利用多态的特性,父类引用子类方法,为什么这么写请看源码
*/
@Override
protected Object determineCurrentLookupKey() {
String key = DynamicDataSource.getDataSources();
if (StringUtils.isNotBlank(key) && !"dataSource".equalsIgnoreCase(key) && dataSourceMap.size() > 1) {
setTargetDataSources(dataSourceMap);
}
return key;
}
/**
* 从新设置数据源,因为源码会把所有的数据源都遍历和判断,为了提升效率我们手动把自己能够使用的数据源提取出来
*/
@Override
public void setTargetDataSources(Map<Object, Object> targetDataSources) {
// 获得默认的数据源和需要切换的数据源,本程序默认数据源的key为"dataSource",自己私有的数据源为所在的机构id
Map<Object, Object> myDataSources = getMyDataSources(targetDataSources);
super.setTargetDataSources(myDataSources);
super.setDefaultTargetDataSource(myDataSources.get("dataSource"));
super.afterPropertiesSet();
}
/**
* 获取自己能够使用的数据源
*
* @param targetDataSources
* @return
*/
private Map<Object, Object> getMyDataSources(Map<Object, Object> targetDataSources) {
Map<Object, Object> myDataSources = new HashMap<>();
String myDataSourcesKey = DynamicDataSource.getDataSources();
myDataSources.put("dataSource", targetDataSources.get("dataSource"));
if (StringUtils.isNotBlank(myDataSourcesKey)) {
Object dataSource = targetDataSources.get(myDataSourcesKey);
if(dataSource != null){
myDataSources.put(myDataSourcesKey, dataSource);
}
}
return myDataSources;
}
/**
* 添加数据源
*
* @param dataSourceName
* @param dataSource
*/
public void addDataSourceMap(String dataSourceName, DataSource dataSource) {
dataSourceMap.put(dataSourceName, dataSource);
}
/**
* 初始化监听器时候会调用此方法把配置文件配置的数据源传入过来
*
* @param dataSource
*/
public void setInitDataSource(DataSource dataSource) {
dataSourceMap.put("dataSource", dataSource);
}
/**
* 获取内置对象
*
* @return
*/
public static DynamicDataSource getObj() {
return obj;
}
}
2.修改spring与mybatis整合的配置文件:
<bean id="dataSource" class="com.immo.ssm.common.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="dataSource" value-ref="defaultTargetDataSource"/>
</map>
</property>
<!--默认数据源-->
<property name="defaultTargetDataSource" ref="defaultTargetDataSource"/>
</bean>
3.我们需要写一个监听器,在项目启动的时候注入默认的数据源到map里面
代码如下:
package com.immo.ssm.listener;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Repository;
import com.alibaba.druid.pool.DruidDataSource;
import com.immo.ssm.common.DynamicDataSource;
import com.immo.ssm.common.Globals;
import com.immo.ssm.entity.BaseFunction;
import com.immo.ssm.entity.BaseMenu;
import com.immo.ssm.service.BaseFunctionService;
import com.immo.ssm.service.BaseMenuService;
@SuppressWarnings("rawtypes")
@Repository
public class InitListener implements ApplicationListener {
// 在web 项目中(spring mvc),系统会存在两个容器
// 一个是root application context ,另一个就是我们自己的 projectName-servlet
// context(作为root application context的子容器)
// 这种情况下,就会造成onApplicationEvent方法被执行两次。
private static boolean isStart = false;
@Autowired
private BaseMenuService baseMenuService;
@Autowired
private BaseFunctionService baseFunctionService;
@Autowired
private DruidDataSource dataSource;
@Override
public void onApplicationEvent(ApplicationEvent event) {
try {
if (!InitListener.isStart) {
InitListener.isStart = true;
List<BaseMenu> selectAllMenus = baseMenuService.selectAllMenus();
Globals.setMenus(selectAllMenus);
List<BaseFunction> selectAllFunction = baseFunctionService.selectAllFunction();
Globals.setFunctions(selectAllFunction);
DynamicDataSource.getObj().setInitDataSource(dataSource);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
这样就已经配置完成了,开始测试步骤
1.创建数据源,例如
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setInitialSize(initialSize);
dataSource.setMaxActive(maxActive);
dataSource.setMaxIdle(maxIdle);
dataSource.setMinIdle(minIdle);
dataSource.setMaxWait(maxWait);
2.调用DynamicDataSource的addDataSourceMap方法存入spring的数据源容器
DynamicDataSource.getObj().addDataSourceMap(dataSourceName, dataSource);
3.切换数据源的话就只需要调用DynamicDataSource的setDataSources方法,传入需要切换的数据源名称即可