继承Spring AbstractRoutingDataSource实现路由切换

下面是结合项目整理的如何实现Spring下数据路由动态切换,分三部分,1.配置文件。2.java类。3.总结

一:配置文件

dataAnt.properties:

driverClass1=oracle.jdbc.driver.OracleDriver
jdbcUrl1=jdbc\:oracle\:thin\:@136.160.40.36\:1521\:crmtemp
db.user1=crm_app
db.password1=abc123

driverClass2=oracle.jdbc.driver.OracleDriver
jdbcUrl2=jdbc\:oracle\:thin\:@136.160.40.36\:1521\:crmtest
db.user2=crm_app
db.password2=abc123
配置文件,两个jdbc的配置


sm-spring-db.xml:

	<!-- dataAnt默认数据源 -->
	<bean id="smDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${driverClass1}">
		</property>
		<property name="url" value="${jdbcUrl1}">
		</property>
		<property name="username" value="${db.user1}">
		</property>
		<property name="password" value="${db.password1}">
		</property>
		<property name="accessToUnderlyingConnectionAllowed">
			<value>true</value>
		</property>
	</bean>
	
	<!-- 数据迁移目标数据源 -->
	<bean id="qyDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${driverClass2}">
		</property>
		<property name="url" value="${jdbcUrl2}">
		</property>
		<property name="username" value="${db.user2}">
		</property>
		<property name="password" value="${db.password2}">
		</property>
		<property name="accessToUnderlyingConnectionAllowed">
			<value>true</value>
		</property>
	</bean>
	

	<!-- 数据路由dataSource-->
	<bean id="dataSource" class="com.ai.data.common.LinkageRoutingDataSource">
		<property name="targetDataSources">
			<map key-type="java.lang.String">
				<entry value-ref="smDataSource" key="smDataSource"></entry>
				<entry value-ref="qyDataSource" key="qyDataSource"></entry>
			</map>
		</property>
		<property name="defaultTargetDataSource" ref="smDataSource"></property>      <!-- 默认使用ds1的数据源 -->
	</bean>
1.这里,配置了两个数据源smDataSource,qyDataSource,并且通过类LinkageRoutingDataSource类实现路由切换。注意设置Bean id为dataSource,保证后面事物控制到对应数据源。

2.bean id = 'dataSource'里注意,必须设置目标数据源targetDataSource和defaultTargetDataSource。


注入jdbcTemplate工具类:

<!--注入JdbcTemplate切换dataSource工具类[获取bean名,重设dataSource] -->
	<bean class="com.ai.data.common.JdbcTemplateUtil"></bean>



二:java类

LinkageRoutingDataSource.java

package com.ai.data.common;

import org.apache.commons.lang.StringUtils;
import org.arrow.common.utils.Log;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * 设置数据源
 *
 * @author weiweiai
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class LinkageRoutingDataSource extends AbstractRoutingDataSource { 
	private static final Log log = Log.getLog(LinkageRoutingDataSource.class);
	
	//目标数据源
	private static final ThreadLocal<String> TARGET_DATA_SOURCE = new ThreadLocal<String>();
	//默认数据源--指标监控的
	public static final String DEFAULT_DATA_SOURCE = "smDataSource";
	
	/**
	 * 根据PrvncUtil类设置进去的当前线程数据源进行数据源切换
	 * 
	 * @param 无
	 * @return 数据源名称
	 */
    protected Object determineCurrentLookupKey() {
    	String targetDataSource = TARGET_DATA_SOURCE.get();
		if (StringUtils.isEmpty(targetDataSource)) {
			targetDataSource = DEFAULT_DATA_SOURCE;	//默认数据源为指标监控数据源
			TARGET_DATA_SOURCE.set(targetDataSource);
		}
		log.debug("当前线程数据源----------------:{}", targetDataSource);
		return targetDataSource;
    }  
    
    /**
     * 设置数据源名
	 * @param target
	 */
	public static void setTargetDataSource(String target) {
		TARGET_DATA_SOURCE.set(target);
	}
	
	/**
	 * 取数据源名
	 * @return
	 */
	public static String getTargetDataSource(){
		return TARGET_DATA_SOURCE.get();
	}
	
	
}

1.实现Spring提供的AbstractRoutingDataSource抽象类,利用ThreadLocal类型来定义TARGET_DATA_SOURCE(目标数据源),保证线程间数据源名不互相影响。

2.指定默认数据源名,对应第一步中bean id =‘smDataSource’

3.determineCurrentLookupKey这个方法,个人理解,如下图:意思应该是说code想建立数据源连接时候,此方法就会执行目的是找到合适数据源。



这里代码里,就是先取TARGET_DATA_SOURCE线程变量里线程安全的TARGET_DATA_SOURCE,取不到就用默认数据源smDataSource。从而实现bean id='dataSource'属性targetDataSources切换。


PrvncUtil.java

package com.ai.data.common;

import org.apache.commons.lang.StringUtils;
import org.arrow.common.utils.Log;

/**
 * 设置获取当前线程数据源名称
 * 
 * @date 20150924
 * @author weiweiai
 */
public class PrvncUtil {
	
	private static final Log LOG_OUTPUT = Log.getLog(PrvncUtil.class);
  
	//默认数据源
	public static final String DEFAULT_DATA_SOURCE = "smDataSource";
	
    /**
     * 设置需要用的数据源名称
     * 
     * @param dataSourceName 数据源名称
     * @retrun 无
     */
    public static void setDataSourceName(String dataSourceName) {  
    	LinkageRoutingDataSource.setTargetDataSource(getDataSourceName(dataSourceName));
    }  
    
    /**
     * 获取数据源名称
     * @param dataSourceName
     * @return 数据源名称
     */
    public static String getDataSourceName(String dataSourceName) {
    	String dataSource = dataSourceName;
    	if(StringUtils.isEmpty(dataSource)){
    		dataSource = DEFAULT_DATA_SOURCE;
    	}
    	LOG_OUTPUT.debug("最终获取到的当前数据源名称:{}", dataSource);
    	//((JdbcTemplate)SpringContextHolder.getBean("jdbcTemplate")).setDataSource((DataSource)SpringContextHolder.getBean(dataSource));
        return dataSource;  
    }  
}  
数据路由切换工具类


JdbcTemplateUtil.java

package com.ai.data.common;

import javax.sql.DataSource;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.jdbc.core.JdbcTemplate;
import com.linkage.bss.commons.util.StringUtil;


/**
 * JdbcTemplate工具类,实现切换数据源后JdbcTemplate数据源重设
 * @author weiweiai
 * 2016/5/10
 *
 */
public class JdbcTemplateUtil implements ApplicationContextAware{

	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	private ApplicationContext ctx;
	
	/*
	 * (non-Javadoc)
	 * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
	 */
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		// TODO Auto-generated method stub
		this.ctx = applicationContext;
	}
	
	/*
	 * 取LinkageRoutingDataSource 线程变量中数据源,重设jdbcTemplate的数据源属性
	 */
	public JdbcTemplate getJdbcTemplate(){
		String ds = LinkageRoutingDataSource.getTargetDataSource();
        if(!StringUtil.isEmpty(ds))
        	jdbcTemplate.setDataSource((DataSource)ctx.getBean(ds));
        return jdbcTemplate;
	}
}
1.实现ApplicationContextAware接口,且在第一步中已引入,作用是获取到Spring容器中注入的bean。

2.getJdbcTemplate()方法,先获取LinkageRoutingDataSource类中TARGET_DATA_SOURCE线程变量中保存的数据源名。

3.ds为空,返回的是默认数据源;否则切换jdbcTemplate的数据源。



调用:

				PrvncUtil.setDataSourceName("qyDataSource");
				primaryValueList = jdbcTemplateUtil.getJdbcTemplate().queryForList((String) dataMap.get("SELFORPRIMARY"));



三:总结

				PrvncUtil.setDataSourceName("qyDataSource");
实现了切换:




primaryValueList = jdbcTemplateUtil.getJdbcTemplate().queryForList((String) dataMap.get("SELFORPRIMARY"));

实现了:


这里为什么jdbcTemplate已经指到dataSource.而dataSource也已经改变属性targetDataSource却没用,我也不懂,欢迎大神指导原因。我已经亲试,确实需要手工

jdbcTemplate.setDataSource((DataSource)ctx.getBean(ds))
不然数据源切不过来,已验证。



  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值