spring多数据源配置实现动态或手动切换

  1. 编写DynamicDataSourceHolder类
public class DynamicDataSourceHolder {
	/**
	 * 注意:数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰
	 */
	private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>();

	public static String getDataSource() {
		return THREAD_DATA_SOURCE.get();
	}

	public static void setDataSource(String dataSource) {
		THREAD_DATA_SOURCE.set(dataSource);
	}

	public static void clearDataSource() {
		THREAD_DATA_SOURCE.remove();
	}
}
  1. 编写DynamicDataSource 继承 AbstractRoutingDataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource{

	@Override
	protected Object determineCurrentLookupKey() {
		return DynamicDataSourceHolder.getDataSource();
		// 从自定义的位置获取数据源标识
	}
}
  1. 编写@interface 自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;



@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
	String value();
}
  1. 编写aop进行自动切换
import java.lang.reflect.Method;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;

public class DataSourceAspect {
	
	Logger logger = LogManager.getLogger(this.getClass());
	
	public void intercept(JoinPoint point) {
		Class<?> target = point.getTarget().getClass();
		MethodSignature signature = (MethodSignature) point.getSignature();
		for (Class<?> clazz : target.getClasses()) {
			resolveDataSource(clazz, signature.getMethod());
		}
		resolveDataSource(target, signature.getMethod());
	}

	private void resolveDataSource(Class<?> clazz, Method method) {
		try {
			Class<?>[] types = method.getParameterTypes();
			// 默认使用类型注解
			if (clazz.isAnnotationPresent(DataSource.class)) {
				DataSource source = clazz.getAnnotation(DataSource.class);
				DynamicDataSourceHolder.setDataSource(source.value());
			}
			// 方法注解可以覆盖类型注解
			
			Method m = clazz.getMethod(method.getName(), types);
			if (m != null && m.isAnnotationPresent(DataSource.class)) {
				DataSource source = m.getAnnotation(DataSource.class);
				DynamicDataSourceHolder.setDataSource(source.value());
			}
		} catch (Exception e) {
			logger.error("反射数据源注解失败");
 		}
	}
}
  1. context.xml配置
<bean id="dataSource1" class="org.springframework.jndi.JndiObjectFactoryBean">
	...........
</bean>

<bean id="dataSource2" class="org.springframework.jndi.JndiObjectFactoryBean">
	...........
</bean>

<bean id="dynamicDataSource" class="com.phfund.datasource.DynamicDataSource">
		<property name="targetDataSources">
			<map key-type="java.lang.String">
				<entry key="d1" value-ref="dataSource1"></entry>
				<entry key="d2" value-ref="dataSource2"></entry> 
			</map>
		</property>
		<!--默认数据源
		<property name="defaultTargetDataSource" ref="dataSource1" />
</bean>

    <!-- 定义事务管理器 -->
<bean id="txManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dynamicDataSource" />
</bean>

 <bean id="dataSourceAspect" class="com.phfund.datasource.aop.DataSourceAspect">
  </bean>
  
 <aop:config proxy-target-class="true">
    	<aop:aspect ref="dataSourceAspect" order="1">
			<aop:pointcut id="dataSourcePointcut"
				expression="execution(* com.phfund.*.service.*.*(..))" />
			<aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
		</aop:aspect>
 </aop:config>
  1. web.xml配置
<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:context.xml</param-value>
</context-param>
  1. 解释
***如果手动切换只需要在查询前使用如下:
		DynamicDataSourceHolder.setDataSource("d1");  [d1,d2] 分别对应下面entry中的key值
		
		<bean id="dynamicDataSource" class="com.phfund.datasource.DynamicDataSource">
				<property name="targetDataSources">
					<map key-type="java.lang.String">
						<entry key="d1" value-ref="dataSource1"></entry>
						<entry key="d2" value-ref="dataSource2"></entry> 
					</map>
				</property>
				<!--默认数据源
				<property name="defaultTargetDataSource" ref="dataSource1" />
		</bean>

****动态切换只需要在aop拦截的方法上面加上自定义注解@DataSource("d1")就能实现动态切换

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值