永远不要跟别人比幸运,我从来没想过我比别人幸运,我也许比他们更有毅力,在最困难的时候,他们熬不住了,我可以多熬一秒钟、两秒钟,甚至更久。

spring 实现多数据源配置

Java 新民 2833℃ 已收录 20评论

前一段时间研究了一下spring多数据源的配置和使用,为了后期从多个数据源拉取数据定时进行数据分析和报表统计做准备。由于之前做过的项目都是单数据源的,没有遇到这种场景,所以也一直没有去了解过如何配置多数据源。
后来发现其实基于spring来配置和使用多数据源还是比较简单的,因为spring框架已经预留了这样的接口可以方便数据源的切换。
先看一下spring获取数据源的源码:

spring框架的AbstractRoutingDataSource中:

第一步,创建一个DynamicDataSource 类,来继承AbstractRoutingDataSource ,重写determineCurrentLookupKey()方法:

 

	package com.xy.common.core;

	import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

	/**
	 * 动态数据源类
	 * @author zhaoxinmin
	 *
	 */
	public class DynamicDataSource extends AbstractRoutingDataSource {

		@Override
		protected Object determineCurrentLookupKey() {
			// TODO Auto-generated method stub
			return DataSourceContextHolder.getDataSource();
		}

	}

第二步:创建DataSourceContextHolder用于持有当前线程中使用的数据源标识,代码如下:

	/**
	 * 数据源处理类
	 * @author zhaoxinmin
	 *
	 */
	public class DataSourceContextHolder {

		private static final ThreadLocal CONTEXTHOLDER = new ThreadLocal();
		
		/**
		 * 获取数据源
		 * @return
		 */
		public static String getDataSource(){
			return CONTEXTHOLDER.get();
		}
		
		/**
		 * 设置数据源
		 * @param dataSurce
		 */
		public static void setDataSource(String dataSurce){
			 CONTEXTHOLDER.set(dataSurce);
		}
		
		/**
		 * 删除数据源  慎用
		 */
		public static void removeDataSource(){
			CONTEXTHOLDER.remove();
		}
		
	}

第三步,在spring配置文件中配置DynamicDataSource 的bean:

	<!-- 配置多数据源-->
	<bean id="dynamicDataSource" class="com.xy.common.core.DynamicDataSource">
		<property name="targetDataSources">
			<map key-type="java.lang.String">
				<entry key="dataSource" value-ref="dataSource" />
				<entry key="dataSource2" value-ref="dataSource2" />
				<entry key="dataSource3" value-ref="dataSource3" />
			</map>
		</property>
		<property name="defaultTargetDataSource" ref="dataSource" />
	</bean> 

第四部,自定义注解DataSource,用来在再dao层描述数据源,可用在类上也可用在方法上:

	package com.xy.common.annotation;

	import java.lang.annotation.ElementType;
	import java.lang.annotation.Retention;
	import java.lang.annotation.RetentionPolicy;
	import java.lang.annotation.Target;

	/**
	 * 自定义注解
	 * 用于动态描述数据源
	 * @author zhaoxinmin
	 *
	 */
	@Target(value={ElementType.TYPE,ElementType.METHOD})
	@Retention(RetentionPolicy.RUNTIME)
	public @interface DataSource {
		String value() ; 
	}

第五步,创建DataSourceAop切面类,用来获取当前动态数据源的标识:

	package com.xy.common.aop;

	import java.lang.reflect.Method;

	import org.aspectj.lang.JoinPoint;
	import org.aspectj.lang.reflect.MethodSignature;
	import org.slf4j.LoggerFactory;

	import com.xy.common.annotation.DataSource;
	import com.xy.common.core.DataSourceContextHolder;

	/**
	 * 数据源切面
	 * @author zhaoxinmin
	 *
	 */
	public class DataSourceAop  {

		public void intercept(JoinPoint joinPoint){
			LoggerFactory.getLogger(DataSourceAop.class).info("dataSource aop start .....");
			Class< ? extends Object> target = joinPoint.getTarget().getClass();
			MethodSignature signature = (MethodSignature) joinPoint.getSignature();
			for(Class< ?> clazz:target.getInterfaces()){
				getDataSourceFlag(signature.getMethod(), clazz);
			}
			getDataSourceFlag(signature.getMethod(),target);
			LoggerFactory.getLogger(DataSourceAop.class).info("dataSource aop end .....");
		}
		
		private void getDataSourceFlag(Method method,Class< ?> clazz){
			if(	clazz.isAnnotationPresent(DataSource.class) ){
				DataSource dataSource = clazz.getAnnotation(DataSource.class);
				DataSourceContextHolder.setDataSource(dataSource.value());
			}
			
			try {
				Class< ?>[] parameterTypes = method.getParameterTypes();
				Method method2 = clazz.getMethod(method.getName(), parameterTypes);
				if(method2 != null && method2.isAnnotationPresent(DataSource.class)){
					DataSource dataSource = method2.getAnnotation(DataSource.class);
					LoggerFactory.getLogger(DataSourceAop.class).info("数据源是:{}",dataSource.value());
					DataSourceContextHolder.setDataSource(dataSource.value());
				}
			} catch (NoSuchMethodException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SecurityException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
				
			
		}
		
	}

第六步,配置aop切面:

	<!-- 多数据源切面 需要在dao上加注解  -->
	<bean id="dataSourceAop" class="com.xy.common.aop.DataSourceAop"></bean>
	<aop:config>
		<aop:aspect ref="dataSourceAop">
			<aop:pointcut expression="execution(* com.xy.*.dao.*.*(..))" id="dataSourcePointcut"/>
			<aop:before method="intercept" pointcut-ref="dataSourcePointcut"/>
		</aop:aspect>
	</aop:config>

第七步,在dao上家注解:

	@DataSource("dataSource")
	public int updateConsigneeState(CustomerAddress cas);
	/**
	 * 查询所有表名
	 * @return
	 */
	@DataSource("dataSource1")
	public List selecttablenames();
本站文章如未注明,均为原创丨本网站采用BY-NC-SA协议进行授权,转载请注明转自:http://www.snowruin.com/?p=1711
喜欢 (2)or分享 (0)
发表我的评论
取消评论
表情 代码 贴图 加粗 链接 私信 删除线 签到

Hi,请填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(20)条精彩评论。
  1. 毫无疑问,这个是要支持的!
    套图网2018-01-07 15:55 回复| Google Chrome 14.0.802.30| Windows 7
  2. 新年好呀,新年好呀,祝福博主新年好!
    八达网2018-01-02 08:25 回复| Google Chrome 14.0.802.30| Windows 7
  3. 博客大好,让人忘不了!
    菏泽夜生活论坛2017-12-28 11:05 回复| Google Chrome 14.0.802.30| Windows 7
  4. 这样的博客让人禁不住一天来几次!
    促美优品2017-12-18 22:21 回复| Google Chrome 14.0.802.30| Windows 7
  5. 这样精彩的博客越来越少咯!
    中青看点2017-12-15 11:35 回复| Google Chrome 14.0.802.30| Windows 7
  6. 很少能看到这么专注的博客啦!
    约炮把妹2017-12-15 09:48 回复| Google Chrome 14.0.802.30| Windows 7
  7. 一言不发岂能证明我来过了?!
    中医秘方2017-12-12 12:15 回复| Google Chrome 14.0.802.30| Windows 7
  8. 谢谢分享。。。
    JIUCAIJIUCAI2017-12-04 09:56 回复| Firefox 50.0| unknow
  9. 一天不来访,浑身上下痒!
    小吃技术2017-11-27 16:02 回复| Google Chrome 14.0.802.30| Windows 7
  10. 潜心学习,认真拜读!
    三五创业网2017-11-16 20:14 回复| Google Chrome 14.0.802.30| Windows 7
1 2