本文主要研究一下RedisTokenVisitorjava
resp-server-0.16.0/src/main/java/com/github/tonivade/resp/protocol/RedisTokenVisitor.javagit
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<>(); } }
resp-server-0.16.0/src/main/java/com/github/tonivade/resp/protocol/AbstractRedisTokenVisitor.javagithub
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; } }
resp-server-0.16.0/src/main/java/com/github/tonivade/resp/protocol/LambdaRedisTokenVisitor.javaapp
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; } } }
resp-server-0.16.0/src/main/java/com/github/tonivade/resp/protocol/RedisSerializer.javaide
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; } } }
RedisTokenVisitor接口定義了array、status、string、integer、error、unknown方法,並提供了靜態builder方法用於建立LambdaRedisTokenVisitor.Builder;目前RedisSerializer的encodeToken方法建立了匿名AbstractRedisTokenVisitor,提供了一個實現。不過目前這個接口的設計有點壞味道,理論上應該把差別提取到泛型中。ui