spring实现简单的读写分离

浏览:1470 发布日期:2021-03-13 11:43:28

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注解即可。