springboot AOP 多数据源切换

由于需要做多数据源切换,然后想到去年做过一次多数据源切换,但是之前是springmvc的,现在是springboot,两者有所不同,在此做个简单的记录。

第一步还是一样的,写一个DynamicDataSourceHolder,用来获取需要使用的数据源是哪个。

public class DynamicDataSourceHolder {
    private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<>();

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

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

第二步再写一个DynamicDataSource类继承AbstractRoutingDataSource,并重写determineCurrentLookupKey方法。

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceHolder.getDataSource();
    }
}

第三步准备两个数据源(仅做演示效果,大家根据实际情况更改)

spring:
  datasource:
    fop-data:
      url: 
      username: 
      password: 
    big-data:
      url: 
      username: 
      password: 

将数据源注册到spring中

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.fop-data")
    public DruidDataSource dataSource1() throws SQLException {
        DruidDataSource druidDataSource = new DruidDataSource();
        return setDruidDataSourceOther(druidDataSource);
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.big-data")
    public DruidDataSource dataSource2() throws SQLException {
        DruidDataSource druidDataSource = new DruidDataSource();
        return setDruidDataSourceOther(druidDataSource);
    }

第四步配置多数据源,需要注意的是:@Primary一定要加这里,缺失@Primary会导致报错,如果加到其他数据源(如dataSource1)上,会无法切换。

    @Primary
    @Bean
    public DynamicDataSource dynamicDataSource() throws SQLException {
        DynamicDataSource dataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>(16);
        targetDataSources.put("dataSource1",dataSource1());
        targetDataSources.put("dataSource2",dataSource2());
        dataSource.setTargetDataSources(targetDataSources);
        // 默认数据源
        dataSource.setDefaultTargetDataSource(dataSource1());
        return dataSource;
    }

放个缺失@Primary的异常:
Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

ps:起初我随便加了bean的位置,然后切不了…
第五步添加事务管理

    @Bean
    public PlatformTransactionManager transactionManager() throws SQLException {
        return new DataSourceTransactionManager(dynamicDataSource());
    }

补充下DruidDataSource数据源剩下的代码:

private DruidDataSource setDruidDataSourceOther(DruidDataSource druidDataSource) throws SQLException {
        druidDataSource.setInitialSize(5);
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setMinIdle(5);
        druidDataSource.setMaxActive(30);
        druidDataSource.setMaxWait(60000);
        druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
        druidDataSource.setMinEvictableIdleTimeMillis(300000);
        druidDataSource.setTestWhileIdle(true);
        druidDataSource.setTestOnBorrow(false);
        druidDataSource.setTestOnReturn(false);
        druidDataSource.setFilters("stat");
        return druidDataSource;
    }

到这一步已经可以使用了,在访问数据前使用 DynamicDataSourceHolder.setDataSource() 做数据源切换。

下面我们使用AOP + 注解的方式对数据源进行切换:
首先定义注解:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    DataSourceType value();
}

枚举:

public enum DataSourceType {
    FOP_DATA("dataSource1"),
    BIG_DATA("dataSource2");

    public String getValue() {
        return value;
    }

    private String value;
    DataSourceType(String value){
        this.value = value;
    }
}

在需要切换数据源的方法上加上注解,如图:
在这里插入图片描述
再加上AOP切面:

@Component
@Aspect
public class DataSourceAOP {
    @Before("@annotation(source)")
    public void intercept(JoinPoint point,DataSource source){
        DynamicDataSourceHolder.setDataSource(source.value().getValue());
    }
}

这个时候加了注解的可以了,但是还有个问题,当切换数据源之后,没有加注解的也使用了切换之后的数据源了,所以我又加了个默认的数据源

    /**
     * 没有加注解的默认数据源为 FOP_DATA
     */
    @Before("execution(* com.obanks.batch.job.executor.service.*.*(..))")
    public void defIntercept(){
        DynamicDataSourceHolder.setDataSource(DataSourceType.FOP_DATA.getValue());
    }

更:
不好意思,漏了个地方,还有启动类上需要排除 数据源自动配置类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})


有疑问还请评论区留言~

END

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值