Spring有一个AbstractRoutingDataSource类,它是一个实现DataSource的抽象类,它的getConnection()实现基于lookup key来查找数据源。通常我们通过在线程上绑定不同的数据源来实现。
// 动态dataSource类
public class DynamicDataSource extends AbstractRoutingDataSource
{
// 用于在当前线程存储当前的数据源
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
{
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
// 返回当前线程的dataSource key
@Override
protected Object determineCurrentLookupKey()
{
return CONTEXT_HOLDER.get();
}
public static void setDefaultDs()
{
CONTEXT_HOLDER.set("default");
}
public static void setReadDs()
{
CONTEXT_HOLDER.set("read");
}
}这个类设置默认的数据源,与一个数据源列表,可通过在线程中去切换要使用的数据源。
创建一个自定义注解,用于在aop中使用。
// 只读DataSource
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ReadDs
{
}创建处理此注解的切面:
@Aspect
public class DataSourceAspect
{
@Before("@annotation(com.store.service.aops.ReadDs)")
public void setReadDs()
{
System.out.println("执行setReadDs");
DynamicDataSource.setReadDs();
}
}在JavaConfig中配置DataSource和切面,不要忘了在配置文件中启用aop - @EnableAspectJAutoProxy:
@Bean
public DataSource dynamicDataSource()
{
DataSource defaultDs = defaultDataSource();
Map<Object, Object> map = new HashMap<>();
map.put("default", defaultDs);
map.put("read", readDataSource());
return new DynamicDataSource(defaultDs, map);
}
@Bean
public DataSourceAspect dataSourceAspect()
{
return new DataSourceAspect();
}在需要启用读写分离的方法上添加我们创建的@ReadDs注解即可。