ssm-alibaba連接池多數據源配置

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

3.切換數據源的話就只需要調用DynamicDataSource的setDataSources方法,傳入需要切換的數據源名稱即可


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章