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();
}
}
}
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);