关于java:MyBatisPlus-动态数据源

MyBatis-Plus 动静数据源须要引入jar包

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.3.1</version>
</dependency>

应用@DS()注解,括号内的值是咱们配置的数据源名称,通常应用的时候是配置到mapper层的类上;如果没有该注解则应用的是默认数据库;
@DS 的优先级也是就近准则,如果类上已有@DS且他的某个办法也有@DS那么该办法应用的数据库为办法上申明的数据库;
有些时候不同库中有雷同的表(对应一个实体类),须要在运行时动静抉择数据源。咱们能够在应用@DS注解的时候,应用#通配符,将咱们的数据库以参数的形式来启用;#参数名称能够动静的应用咱们的参数变量或者header和session中的变量;

‘#’参数的实现依赖于com.baomidou.dynamic.datasource.processorDsProcessor接口解决,实现形式有三个

  1. DsHeaderProcessor: 从申请的header中获取ds数据源名称。
  2. DsSessionProcessor: 从session中获取数据源d名称
  3. DsSpelExpressionProcessor: 通过spel表达式获取ds数据源名称,

这3种形式采纳的是责任链形式间断获取的。顺次执行。


DsHeaderProcessor的拦挡格局为@DS("#header 变量名")
@DS("#header dataName")
List<Entity> List(@Param("query") String query

DsSessionProcessor的拦挡格局为@DS("#session 变量名")
@DS("#session dataName")
List<Entity> List(@Param("query") String query

@DS("#dataName")
List<Entity> List(@Param("query") String query, String dataName);

其实现原理为DynamicDataSourceAutoConfiguration配置类Advisor

  @Bean
  @ConditionalOnMissingBean
  public DynamicDataSourceAnnotationAdvisor dynamicDatasourceAnnotationAdvisor(DsProcessor dsProcessor) {
    DynamicDataSourceAnnotationInterceptor interceptor = new DynamicDataSourceAnnotationInterceptor();
    interceptor.setDsProcessor(dsProcessor);
    DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(interceptor);
    advisor.setOrder(properties.getOrder());
    return advisor;
  }

DynamicDataSourceAnnotationAdvisor的切点为DS注解

  private Pointcut buildPointcut() {
    Pointcut cpc = new AnnotationMatchingPointcut(DS.class, true);
    Pointcut mpc = AnnotationMatchingPointcut.forMethodAnnotation(DS.class);
    return new ComposablePointcut(cpc).union(mpc);
  }

拦截器为DynamicDataSourceAnnotationInterceptor,拦截器会解决以#结尾的注解值,并交由
DsProcessor来解决

  private static final String DYNAMIC_PREFIX = "#";

  private String determineDatasource(MethodInvocation invocation) throws Throwable {
    Method method = invocation.getMethod();
    DS ds = method.isAnnotationPresent(DS.class)
        ? method.getAnnotation(DS.class)
        : AnnotationUtils.findAnnotation(RESOLVER.targetClass(invocation), DS.class);
    String key = ds.value();
    return (!key.isEmpty() && key.startsWith(DYNAMIC_PREFIX)) ? dsProcessor
        .determineDatasource(invocation, key) : key;
  }

DsHeaderProcessor解决逻辑为从request的header中取变量值:

  private static final String HEADER_PREFIX = "#header";

  @Override
  public boolean matches(String key) {
    return key.startsWith(HEADER_PREFIX);
  }

  @Override
  public String doDetermineDatasource(MethodInvocation invocation, String key) {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
        .getRequestAttributes()).getRequest();
//这一行能够看出HEADER_PREFIX 和数据源之间须要空一位,能够使任意字符
    return request.getHeader(key.substring(8));
  }

DsSessionProcessor 从seesion中去取变量的值:

  private static final String SESSION_PREFIX = "#session";

  @Override
  public boolean matches(String key) {
    return key.startsWith(SESSION_PREFIX);
  }

  @Override
  public String doDetermineDatasource(MethodInvocation invocation, String key) {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
        .getRequestAttributes()).getRequest();
//这一行能够看出SESSION_PREFIX 和数据源之间须要空一位,能够使任意字符
    return request.getSession().getAttribute(key.substring(9)).toString();
  }

DsSpelExpressionProcessor:


  /**
   * 参数发现器
   */
  private static final ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
  /**
   * Express语法解析器
   */
  private static final ExpressionParser PARSER = new SpelExpressionParser();

  @Override
  public boolean matches(String key) {
    return true;
  }

  @Override
  public String doDetermineDatasource(MethodInvocation invocation, String key) {
    Method method = invocation.getMethod();
    Object[] arguments = invocation.getArguments();
    EvaluationContext context = new MethodBasedEvaluationContext(null, method, arguments,
        NAME_DISCOVERER);
    final Object value = PARSER.parseExpression(key).getValue(context);
    return value == null ? null : value.toString();
  }

具体的实现原理能够参考 Spring 动静数据源,源码入口为:`
com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理