- 编写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();
}
}
- 编写DynamicDataSource 继承 AbstractRoutingDataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSource();
// 从自定义的位置获取数据源标识
}
}
- 编写@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();
}
- 编写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("反射数据源注解失败");
}
}
}
- 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>
- web.xml配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:context.xml</param-value>
</context-param>
- 解释
***如果手动切换只需要在查询前使用如下:
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")就能实现动态切换