package org.kyrin.koala.datasource; import java.util.List; import java.util.Map; import java.util.Stack; import org.apache.log4j.Logger; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * *********************** * * 动态数据源 * * *********************** * @author kyrin kyrincloud@qq.com * * @date [2015年5月2日] * */ public class DynamicDataSource extends AbstractRoutingDataSource implements ApplicationContextAware{ private static Logger logger=Logger.getLogger(DynamicDataSource.class); private static ApplicationContext applicationContext; private Map<Object,Object> targetDataSources; private Map<Object,List<String>> dataSourceKeysGroup; private static final String DEFAULT_TARGET_DATASOURCE="defaultTargetDataSource"; private static final ThreadLocal<Stack<String>> threadLocal=new ThreadLocal<Stack<String>>(){ @Override protected Stack<String> initialValue() { return new Stack<String>(); } }; @SuppressWarnings("static-access") @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext=applicationContext; } @Override public void afterPropertiesSet() { if(targetDataSources==null){ logger.error("The dataSources property is null "); throw new IllegalArgumentException("dataSources is null"); } if(targetDataSources.get(DEFAULT_TARGET_DATASOURCE)==null){ logger.error("Not set the key of 'defaultTargetDataSource' "); throw new IllegalArgumentException("Please set the key 'defaultTargetDataSource'"); } super.setTargetDataSources(targetDataSources); super.setDefaultTargetDataSource(targetDataSources.get(DEFAULT_TARGET_DATASOURCE)); super.afterPropertiesSet(); } public static void changeTo(String target){ logger.info("Change current dataSource to "+target); Stack<String> current=threadLocal.get(); current.push(target); } public void changeToByGroup(String groupName){ if(dataSourceKeysGroup==null){ throw new IllegalArgumentException("Not set the property 'dataSourceKeysGroup'"); } List<String> dataSourceKeys=dataSourceKeysGroup.get(groupName); if(dataSourceKeys==null || dataSourceKeys.size()==0){ throw new IllegalArgumentException("Not set the groupName "+groupName); } Stack<String> current=threadLocal.get(); String key=dataSourceKeys.get(0); if(!targetDataSources.containsKey(key)){ logger.error(" The dataSource key "+key+" is wrong"); throw new IllegalArgumentException("Error dataSource key "+key); } current.push(key); logger.info("Change current dataSource to "+key+" by dataSourceKeyGroup"); reordering(dataSourceKeys); } private void reordering(List<String> dataSourceKeys){ //首尾调换位置,实现队列轮训的形式 String first=dataSourceKeys.get(0); dataSourceKeys.remove(0); dataSourceKeys.add(first); } @Override protected Object determineCurrentLookupKey() { Stack<String> current=threadLocal.get(); if(current.isEmpty()) return ""; String name=current.pop() ; return name== null ? "" : name; } public static DynamicDataSource getInstance(){ return (DynamicDataSource) applicationContext.getBean(DynamicDataSource.class); } public Map<Object, Object> getTargetDataSources() { return targetDataSources; } public void setTargetDataSources(Map<Object, Object> targetDataSources) { this.targetDataSources = targetDataSources; } public Map<Object, List<String>> getDataSourceKeysGroup() { return dataSourceKeysGroup; } public void setDataSourceKeysGroup(Map<Object, List<String>> dataSourceKeysGroup) { this.dataSourceKeysGroup = dataSourceKeysGroup; } }