重写路由_ShardingJDBC源码阅读(六)重写

e141a5de53c509cfb74b104b9efd959e.png

前言

6229d61212c74591c240e5800d672562.png

本章分析ShardingJDBC的核心步骤:重写

一、SQL重写入口

回到BasePrepareEngine#prepare,经过路由处理后最终得到RouteContext,进入executeRewrite重写流程。

public ExecutionContext prepare(final String sql, final List parameters) {
    
  List clonedParameters = cloneParameters(parameters);// 解析 & 路由
  RouteContext routeContext = executeRoute(sql, clonedParameters);
  ExecutionContext result = new ExecutionContext(routeContext.getSqlStatementContext());// 重写
  Collection executionUnits = executeRewrite(sql, clonedParameters, routeContext);
  result.getExecutionUnits().addAll(executionUnits);// 打印SQLif (properties.getValue(ConfigurationPropertyKey.SQL_SHOW)) {
      SQLLogger.logSQL(sql, properties.getValue(ConfigurationPropertyKey.SQL_SIMPLE), result.getSqlStatementContext(), result.getExecutionUnits());
  }return result;
}

BasePrepareEngine#executeRewrite重写流程分为三步:

1. 注册SQLRewriteContextDecorator到SQLRewriteEntry。

2. SQLRewriteEntry创建SQLRewriteContext,重写参数列表,创建SQLToken。

3. 执行重写引擎SQLRouteRewriteEngine,重写sql,拼装参数列表。

private Collection executeRewrite(final String sql, final List parameters, final RouteContext routeContext) {
    
  // 注册 BaseRule(ShardingRule)和对应SQL重写处理类 SQLRewriteContextDecorator 到SQLRewriteEntry(rewriter)
  registerRewriteDecorator();
  // 创建SQLRewriteContext,重写参数列表,创建SQLToken
  SQLRewriteContext sqlRewriteContext = rewriter.createSQLRewriteContext(sql, parameters, routeContext.getSqlStatementContext(), routeContext);
  if (routeContext.getRouteResult().getRouteUnits().isEmpty()) {
      // 路由结果是空 比如走了ShardingIgnoreRoutingEngine(use xxx)
      return rewrite(sqlRewriteContext);
  } else {
      // SQLRouteRewriteEngine 重写引擎执行(通常走这里)
      return rewrite(routeContext, sqlRewriteContext);
  }
}
280b36fdb2c19c2aec6b260ab0aa89b9.png

二、注册装饰器

BasePrepareEngine#executeRewrite的第一步,就是将SQLRewriteContextDecorator注册到SQLRewriteEntry。这里一步类似于路由流程中BasePrepareEngine#registerRouteDecorator注册RouteDecorator到DataNodeRouter。

private void registerRewriteDecorator() {
    
  for (Class extends SQLRewriteContextDecorator> each : OrderedRegistry.getRegisteredClasses(SQLRewriteContextDecorator.class)) {
      SQLRewriteContextDecorator rewriteContextDecorator = each.newInstance();
      Class> ruleClass = (Class>) rewriteContextDecorator.getType();
      rules.stream().filter(rule -> rule.getClass() == ruleClass || rule.getClass().getSuperclass() == ruleClass).collect(Collectors.toList())
              // 放入SQLRewriteEntry的Map
              .forEach(rule -> rewriter.registerDecorator(rule, rewriteContextDecorator));
  }
}

三、SQLRewriteEntry

SQLRewriteEntry负责创建SQLRewriteContextsql重写上下文,重写参数列表,创建SQLToken。

public final class SQLRewriteEntry {
    
  // 表的元数据信息
  private final SchemaMetaData schemaMetaData;
  // 配置
  private final ConfigurationProperties properties;
  // BaseRule - SQLRewriteContextDecorator
  private final Map decorators = new LinkedHashMap<>();
}

暴露两个公共方法:

  1. registerDecorator方法:注册SQLRewriteContextDecorator,这个在BasePrepareEngine#executeRewrite的第一步执行了。
private final Map decorators = new LinkedHashMap<>();public void registerDecorator(final BaseRule rule, final SQLRewriteContextDecorator decorator) {
    
  decorators.put(rule, decorator);
}
  1. createSQLRewriteContext方法:创建SQLRewriteContext并执行所有SQLRewriteContextDecorator,创建SQLToken,这是BasePrepareEngine#executeRewrite的第二步。
public SQLRewriteContext createSQLRewriteContext(final String sql, final List parameters, final SQLStatementContext sqlStatementContext, final RouteContext routeContext) {
    
  SQLRewriteContext result = new SQLRewriteContext(schemaMetaData, sqlStatementContext, sql, parameters);
  // 执行所有SQLRewriteContextDecorator,其中重写参数列表
  decorate(decorators, result, routeContext);
  // 创建SQLToken
  result.generateSQLTokens();
  return result;
}

private void decorate(final Map decorators, final SQLRewriteContext sqlRewriteContext, final RouteContext routeContext) {
  for (Entry entry : decorators.entrySet()) {
      BaseRule rule = entry.getKey();
      SQLRewriteContextDecorator decorator = entry.getValue();if (decorator instanceof RouteContextAware) {
          ((RouteContextAware) decorator).setRouteContext(routeContext);
      }
      decorator.decorate(rule, properties, sqlRewriteContext);
  }
}

SQLRewriteContextDecorator

SQLRewriteContextDecorator,一般情况下要做两个事情:

  • 参数重写,执行ParameterRewriter集合,将重写相关信息保存到SQLRewriteContext#parameterBuilder中
  • 创建SQLTokenGenerator集合,保存到SQLRewriteContext#sqlTokenGenerators中

SQLRewriteContextDecorator有三个实现:

  • EncryptSQLRewriteContextDecorator负责数据脱敏。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值