baomidou的dynamic-datasource读写分离实现和加入AOP根据方法名选择库

文档

https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter/wikis/pages

maven

  1.  
    <dependency>
  2.  
    <groupId>com.baomidou</groupId>
  3.  
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  4.  
    <version>2.5.7</version>
  5.  
    </dependency>

纯读写分离(mybatis环境)

场景:

  1. 在纯的读写分离环境,写操作全部是master,读操作全部是slave。
  2. 不想通过注解配置完成以上功能。

答:在mybatis环境下可以基于mybatis插件结合本数据源完成以上功能。 手动注入插件。

  1.  
    @Bean
  2.  
    public MasterSlaveAutoRoutingPlugin masterSlaveAutoRoutingPlugin(){
  3.  
    return new MasterSlaveAutoRoutingPlugin();
  4.  
    }

默认主库名称master,从库名称slave。

问题

       我在配置好了之后,调试发现对数据库读的操作不得进入MasterSlaveAutoRoutingPlugin,而且进入了默认的库。只有写进入了MasterSlaveAutoRoutingPlugin中。当然也可以默认为从库,但是感觉就不是很好。

       于是我自定义了一个aop切面来,来完成库的选择,代码如下:

  1.  
    import java.lang.reflect.Method;
  2.  
    import org.aspectj.lang.JoinPoint;
  3.  
    import org.aspectj.lang.annotation.After;
  4.  
    import org.aspectj.lang.annotation.Aspect;
  5.  
    import org.aspectj.lang.annotation.Before;
  6.  
    import org.aspectj.lang.annotation.Pointcut;
  7.  
    import org.aspectj.lang.reflect.MethodSignature;
  8.  
    import org.springframework.context.annotation.Lazy;
  9.  
    import org.springframework.core.annotation.Order;
  10.  
    import org.springframework.stereotype.Component;
  11.  
    import com.baomidou.dynamic.datasource.annotation.DS;
  12.  
    import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
  13.  
    import lombok.extern.java.Log;
  14.  
     
  15.  
    /**
  16.  
    * Copyright: Copyright (c) 2019
  17.  
    * <p> 说明:动态数据源配置 </P>
  18.  
    *
  19.  
    * @version: V1.0
  20.  
    * @author: BianPeng
  21.  
    *
  22.  
    */
  23.  
    @Aspect
  24.  
    @Component
  25.  
    @Order(0)
  26.  
    @Lazy(false)
  27.  
    @Log
  28.  
    public class DataSourceAop{
  29.  
     
  30.  
    private static final String MASTER = "master";
  31.  
     
  32.  
    private static final String SLAVE = "slave";
  33.  
     
  34.  
     
  35.  
    @Pointcut("execution(* com.buybit.power.service..*.*(..)) || execution(* com.baomidou.mybatisplus.extension.service..*.*(..))")
  36.  
    public void checkArgs() {
  37.  
    }
  38.  
     
  39.  
    // 这里切到你的方法目录
  40.  
    @Before("checkArgs()")
  41.  
    public void process(JoinPoint joinPoint) throws NoSuchMethodException, SecurityException {
  42.  
    String methodName = joinPoint.getSignature().getName();
  43.  
    if (methodName.startsWith("get")
  44.  
    || methodName.startsWith("count")
  45.  
    || methodName.startsWith("find")
  46.  
    || methodName.startsWith("list")
  47.  
    || methodName.startsWith("select")
  48.  
    || methodName.startsWith("check")
  49.  
    || methodName.startsWith("page")) {
  50.  
     
  51.  
    log.info("当前执行的库:"+SLAVE);
  52.  
    DynamicDataSourceContextHolder.push(SLAVE);
  53.  
    } else {
  54.  
    log.info("当前执行的库:"+MASTER);
  55.  
    DynamicDataSourceContextHolder.push(MASTER);
  56.  
    }
  57.  
    }
  58.  
    @After("checkArgs()")
  59.  
    public void afterAdvice(){
  60.  
    DynamicDataSourceContextHolder.clear();
  61.  
    }
  62.  
    }

但是发现,baomidou/dynamic-datasource自带的@DS没失去了着用,于是我把有@DS的类和方法排除掉,代码入下:

  1.  
    import java.lang.reflect.Method;
  2.  
    import org.aspectj.lang.JoinPoint;
  3.  
    import org.aspectj.lang.annotation.After;
  4.  
    import org.aspectj.lang.annotation.Aspect;
  5.  
    import org.aspectj.lang.annotation.Before;
  6.  
    import org.aspectj.lang.annotation.Pointcut;
  7.  
    import org.aspectj.lang.reflect.MethodSignature;
  8.  
    import org.springframework.context.annotation.Lazy;
  9.  
    import org.springframework.core.annotation.Order;
  10.  
    import org.springframework.stereotype.Component;
  11.  
    import com.baomidou.dynamic.datasource.annotation.DS;
  12.  
    import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
  13.  
    import lombok.extern.java.Log;
  14.  
     
  15.  
    /**
  16.  
    * Copyright: Copyright (c) 2019
  17.  
    * <p> 说明:动态数据源配置 </P>
  18.  
    *
  19.  
    * @version: V1.0
  20.  
    * @author: BianPeng
  21.  
    *
  22.  
    */
  23.  
    @Aspect
  24.  
    @Component
  25.  
    @Order(0)
  26.  
    @Lazy(false)
  27.  
    @Log
  28.  
    public class DataSourceAop{
  29.  
     
  30.  
    private static final String MASTER = "master";
  31.  
     
  32.  
    private static final String SLAVE = "slave";
  33.  
     
  34.  
     
  35.  
    @Pointcut("execution(* com.buybit.power.service..*.*(..)) || execution(* com.baomidou.mybatisplus.extension.service..*.*(..))")
  36.  
    public void checkArgs() {
  37.  
    }
  38.  
     
  39.  
    // 这里切到你的方法目录
  40.  
    @Before("checkArgs()")
  41.  
    public void process(JoinPoint joinPoint) throws NoSuchMethodException, SecurityException {
  42.  
    String methodName = joinPoint.getSignature().getName();
  43.  
    Class clazz = joinPoint.getTarget().getClass();
  44.  
    if(clazz.isAnnotationPresent(DS.class)){
  45.  
    //获取类上注解
  46.  
    return;
  47.  
    }
  48.  
     
  49.  
    String targetName = clazz.getSimpleName();
  50.  
    Class[] parameterTypes =
  51.  
    ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes();
  52.  
    Method methdo = clazz.getMethod(methodName,parameterTypes);
  53.  
    if (methdo.isAnnotationPresent(DS.class)) {
  54.  
    return;
  55.  
    }
  56.  
    if (methodName.startsWith("get")
  57.  
    || methodName.startsWith("count")
  58.  
    || methodName.startsWith("find")
  59.  
    || methodName.startsWith("list")
  60.  
    || methodName.startsWith("select")
  61.  
    || methodName.startsWith("check")
  62.  
    || methodName.startsWith("page")) {
  63.  
     
  64.  
    log.info("当前执行的库:"+SLAVE);
  65.  
    DynamicDataSourceContextHolder.push(SLAVE);
  66.  
    } else {
  67.  
    log.info("当前执行的库:"+MASTER);
  68.  
    DynamicDataSourceContextHolder.push(MASTER);
  69.  
    }
  70.  
    }
  71.  
    @After("checkArgs()")
  72.  
    public void afterAdvice(){
  73.  
    DynamicDataSourceContextHolder.clear();
  74.  
    }
  75.  
    }

这样可以让你有@DS的注解依然生效,而且也会根据方法名来自动切换数据源。

posted @ 2021-01-19 10:49  牧之丨  阅读(1079)  评论(0编辑  收藏  举报