聊聊RedisTokenVisitor

时间:2022-07-23
本文章向大家介绍聊聊RedisTokenVisitor,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

本文主要研究一下RedisTokenVisitor

RedisTokenVisitor

resp-server-0.16.0/src/main/java/com/github/tonivade/resp/protocol/RedisTokenVisitor.java

public interface RedisTokenVisitor<T> {
  T array(ArrayRedisToken token);
  T status(StatusRedisToken token);
  T string(StringRedisToken token);
  T integer(IntegerRedisToken token);
  T error(ErrorRedisToken token);
  T unknown(UnknownRedisToken token);
​
  static <T> LambdaRedisTokenVisitor.Builder<T> builder() {
    return new LambdaRedisTokenVisitor.Builder<>();
  }
}
  • RedisTokenVisitor接口定义了array、status、string、integer、error、unknown方法,并提供了静态builder方法用于创建LambdaRedisTokenVisitor.Builder

AbstractRedisTokenVisitor

resp-server-0.16.0/src/main/java/com/github/tonivade/resp/protocol/AbstractRedisTokenVisitor.java

public abstract class AbstractRedisTokenVisitor<T> implements RedisTokenVisitor<T> {
  @Override
  public T array(ArrayRedisToken token) {
    return null;
  }
​
  @Override
  public T status(StatusRedisToken token) {
    return null;
  }
​
  @Override
  public T string(StringRedisToken token) {
    return null;
  }
​
  @Override
  public T error(ErrorRedisToken token) {
    return null;
  }
​
  @Override
  public T unknown(UnknownRedisToken token) {
    return null;
  }
​
  @Override
  public T integer(IntegerRedisToken token) {
    return null;
  }
}
  • AbstractRedisTokenVisitor实现了RedisTokenVisitor接口,默认返回null

LambdaRedisTokenVisitor

resp-server-0.16.0/src/main/java/com/github/tonivade/resp/protocol/LambdaRedisTokenVisitor.java

class LambdaRedisTokenVisitor<T> implements RedisTokenVisitor<T> {
​
  private Function<ArrayRedisToken, T> onArray;
  private Function<StatusRedisToken, T> onStatus;
  private Function<StringRedisToken, T> onString;
  private Function<ErrorRedisToken, T> onError;
  private Function<IntegerRedisToken, T> onInteger;
  private Function<UnknownRedisToken, T> onUnknown;
​
  LambdaRedisTokenVisitor(
      Function<ArrayRedisToken, T> onArray,
      Function<StatusRedisToken, T> onStatus,
      Function<StringRedisToken, T> onString,
      Function<ErrorRedisToken, T> onError,
      Function<IntegerRedisToken, T> onInteger,
      Function<UnknownRedisToken, T> onUnknown) {
    this.onArray = onArray;
    this.onStatus = onStatus;
    this.onString = onString;
    this.onError = onError;
    this.onInteger = onInteger;
    this.onUnknown = onUnknown;
  }
​
  @Override
  public T array(ArrayRedisToken token) {
    return onArray.apply(token);
  }
​
  @Override
  public T status(StatusRedisToken token) {
    return onStatus.apply(token);
  }
​
  @Override
  public T string(StringRedisToken token) {
    return onString.apply(token);
  }
​
  @Override
  public T error(ErrorRedisToken token) {
    return onError.apply(token);
  }
​
  @Override
  public T unknown(UnknownRedisToken token) {
    return onUnknown.apply(token);
  }
​
  @Override
  public T integer(IntegerRedisToken token) {
    return onInteger.apply(token);
  }
​
  public static class Builder<T> {
    private Function<ArrayRedisToken, T> onArray;
    private Function<StatusRedisToken, T> onStatus;
    private Function<StringRedisToken, T> onString;
    private Function<ErrorRedisToken, T> onError;
    private Function<IntegerRedisToken, T> onInteger;
    private Function<UnknownRedisToken, T> onUnknown;
​
    public Builder<T> onArray(Function<ArrayRedisToken, T> onArray) {
      this.onArray = requireNonNull(onArray);
      return this;
    }
​
    public Builder<T> onStatus(Function<StatusRedisToken, T> onStatus) {
      this.onStatus = requireNonNull(onStatus);
      return this;
    }
​
    public Builder<T> onString(Function<StringRedisToken, T> onString) {
      this.onString = requireNonNull(onString);
      return this;
    }
​
    public Builder<T> onError(Function<ErrorRedisToken, T> onError) {
      this.onError = requireNonNull(onError);
      return this;
    }
​
    public Builder<T> onInteger(Function<IntegerRedisToken, T> onInteger) {
      this.onInteger = requireNonNull(onInteger);
      return this;
    }
​
    public Builder<T> onUnknown(Function<UnknownRedisToken, T> onUnknown) {
      this.onUnknown = requireNonNull(onUnknown);
      return this;
    }
​
    public RedisTokenVisitor<T> build() {
      return new LambdaRedisTokenVisitor<>(
          safe(onArray), safe(onStatus), safe(onString),
          safe(onError), safe(onInteger), safe(onUnknown));
    }
​
    private <X> Function<X, T> safe(Function<X, T> function) {
      return nonNull(function) ? function : x -> null;
    }
  }
}
  • LambdaRedisTokenVisitor实现了RedisTokenVisitor接口,其构造器要求输入onArray、onStatus、onString、onError、onInteger、onUnknown这几个Function

RedisSerializer

resp-server-0.16.0/src/main/java/com/github/tonivade/resp/protocol/RedisSerializer.java

public class RedisSerializer {
  private static final byte ARRAY = '*';
  private static final byte ERROR = '-';
  private static final byte INTEGER = ':';
  private static final byte SIMPLE_STRING = '+';
  private static final byte BULK_STRING = '$';
​
  private static final byte[] DELIMITER = new byte[] { 'r', 'n' };
  private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
​
  private ByteBufferBuilder builder = new ByteBufferBuilder();
​
  public byte[] encodeToken(RedisToken msg) {
    msg.accept(new AbstractRedisTokenVisitor<Void>() {
      @Override
      public Void string(StringRedisToken token) {
        addBulkStr(token.getValue());
        return null;
      }
​
      @Override
      public Void status(StatusRedisToken token) {
        addSimpleStr(token.getValue());
        return null;
      }
​
      @Override
      public Void integer(IntegerRedisToken token) {
        addInt(token.getValue());
        return null;
      }
​
      @Override
      public Void error(ErrorRedisToken token) {
        addError(token.getValue());
        return null;
      }
​
      @Override
      public Void array(ArrayRedisToken token) {
        addArray(token.getValue());
        return null;
      }
    });
    return builder.build();
  }
​
  private void addBulkStr(SafeString str) {
    if (str != null) {
      builder.append(BULK_STRING).append(str.length()).append(DELIMITER).append(str);
    } else {
      builder.append(BULK_STRING).append(-1);
    }
    builder.append(DELIMITER);
  }
​
  private void addSimpleStr(String str) {
    builder.append(SIMPLE_STRING).append(str.getBytes()).append(DELIMITER);
  }
​
  private void addInt(Integer value) {
    builder.append(INTEGER).append(value).append(DELIMITER);
  }
​
  private void addError(String str) {
    builder.append(ERROR).append(str.getBytes()).append(DELIMITER);
  }
​
  private void addArray(Sequence<RedisToken> array) {
    if (array != null) {
      builder.append(ARRAY).append(array.size()).append(DELIMITER);
      for (RedisToken token : array) {
        builder.append(new RedisSerializer().encodeToken(token));
      }
    } else {
      builder.append(ARRAY).append(0).append(DELIMITER);
    }
  }
​
  private static class ByteBufferBuilder {
    private static final int INITIAL_CAPACITY = 1024;
​
    private ByteBuffer buffer = ByteBuffer.allocate(INITIAL_CAPACITY);
​
    private ByteBufferBuilder append(int i) {
      append(String.valueOf(i));
      return this;
    }
​
    private ByteBufferBuilder append(String str) {
      append(str.getBytes(DEFAULT_CHARSET));
      return this;
    }
​
    private ByteBufferBuilder append(SafeString str) {
      append(str.getBytes());
      return this;
    }
​
    private ByteBufferBuilder append(byte[] buf) {
      ensureCapacity(buf.length);
      buffer.put(buf);
      return this;
    }
​
    public ByteBufferBuilder append(byte b) {
      ensureCapacity(1);
      buffer.put(b);
      return this;
    }
​
    private void ensureCapacity(int len) {
      if (buffer.remaining() < len) {
        growBuffer(len);
      }
    }
​
    private void growBuffer(int len) {
      int capacity = buffer.capacity() + Math.max(len, INITIAL_CAPACITY);
      buffer = ByteBuffer.allocate(capacity).put(build());
    }
​
    public byte[] build() {
      byte[] array = new byte[buffer.position()];
      buffer.rewind();
      buffer.get(array);
      return array;
    }
  }
}
  • RedisSerializer的encodeToken方法创建了匿名AbstractRedisTokenVisitor;其string方法执行addBulkStr(token.getValue());其status方法执行addSimpleStr(token.getValue());其integer方法执行addInt(token.getValue());其error方法执行addError(token.getValue());其array方法执行addArray(token.getValue())

小结

RedisTokenVisitor接口定义了array、status、string、integer、error、unknown方法,并提供了静态builder方法用于创建LambdaRedisTokenVisitor.Builder;目前RedisSerializer的encodeToken方法创建了匿名AbstractRedisTokenVisitor,提供了一个实现。不过目前这个接口的设计有点坏味道,理论上应该把差异提取到泛型中。

doc