共计 5445 个字符,预计需要花费 14 分钟才能阅读完成。
序
本文次要钻研一下 RespCommand
RespCommand
resp-server-0.16.0/src/main/java/com/github/tonivade/resp/command/RespCommand.java
@FunctionalInterface | |
public interface RespCommand {RedisToken execute(Request request); | |
} |
- RespCommand 定义了 execute 办法,接管 Request 参数,返回 RedisToken
Request
resp-server-0.16.0/src/main/java/com/github/tonivade/resp/command/Request.java
public interface Request {String getCommand(); | |
ImmutableArray<SafeString> getParams(); | |
SafeString getParam(int i); | |
Option<SafeString> getOptionalParam(int i); | |
int getLength(); | |
boolean isEmpty(); | |
Session getSession(); | |
ServerContext getServerContext(); | |
boolean isExit();} |
- Request 接口定义了 getCommand、getParams、getParam、getOptionalParam、getLength、isEmpty、getSession、getServerContext、isExit 办法
DefaultRequest
resp-server-0.16.0/src/main/java/com/github/tonivade/resp/command/DefaultRequest.java
public class DefaultRequest implements Request { | |
private final SafeString command; | |
private final ImmutableArray<SafeString> params; | |
private final Session session; | |
private final ServerContext server; | |
public DefaultRequest(ServerContext server, Session session, SafeString command, ImmutableArray<SafeString> params) { | |
this.server = server; | |
this.session = session; | |
this.command = requireNonNull(command); | |
this.params = requireNonNull(params); | |
} | |
@Override | |
public String getCommand() {return command.toString(); | |
} | |
@Override | |
public ImmutableArray<SafeString> getParams() {return params;} | |
@Override | |
public SafeString getParam(int i) {if (i < params.size()) {return params.get(i); | |
} | |
return null; | |
} | |
@Override | |
public Option<SafeString> getOptionalParam(int i) {return Option.of(() -> getParam(i)); | |
} | |
@Override | |
public int getLength() {return params.size(); | |
} | |
@Override | |
public boolean isEmpty() {return params.isEmpty(); | |
} | |
@Override | |
public boolean isExit() {return command.toString().equalsIgnoreCase("quit"); | |
} | |
@Override | |
public Session getSession() {return session;} | |
@Override | |
public ServerContext getServerContext() {return server;} | |
@Override | |
public String toString() {return command + "[" + params.size() + "]:" + params; | |
} | |
} |
- DefaultRequest 实现了 Request 接口,它定义了 command、params、session、server 属性,均在结构器中传入
CommandSuite
resp-server-0.16.0/src/main/java/com/github/tonivade/resp/command/CommandSuite.java
public class CommandSuite {private static final Logger LOGGER = LoggerFactory.getLogger(CommandSuite.class); | |
private final Map<String, Class<?>> metadata = new HashMap<>(); | |
private final Map<String, RespCommand> commands = new HashMap<>(); | |
private final NullCommand nullCommand = new NullCommand(); | |
private final CommandWrapperFactory factory; | |
public CommandSuite() {this(new DefaultCommandWrapperFactory()); | |
} | |
public CommandSuite(CommandWrapperFactory factory) { | |
this.factory = factory; | |
addCommand(PingCommand.class); | |
addCommand(EchoCommand.class); | |
addCommand(QuitCommand.class); | |
addCommand(TimeCommand.class); | |
} | |
public RespCommand getCommand(String name) {return commands.getOrDefault(name.toLowerCase(), nullCommand); | |
} | |
public boolean isPresent(String name, Class<? extends Annotation> annotationClass) {return getMetadata(name).isAnnotationPresent(annotationClass); | |
} | |
public boolean contains(String name) {return commands.get(name) != null; | |
} | |
protected void addCommand(Class<?> clazz) {Try.of(clazz::newInstance) | |
.onSuccess(this::processCommand) | |
.onFailure(e -> LOGGER.error("error loading command:" + clazz.getName(), e)); | |
} | |
protected void addCommand(String name, RespCommand command) {commands.put(name.toLowerCase(), factory.wrap(command)); | |
} | |
private void processCommand(Object command) {Class<?> clazz = command.getClass(); | |
Command annotation = clazz.getAnnotation(Command.class); | |
if (annotation != null) {commands.put(annotation.value(), factory.wrap(command)); | |
metadata.put(annotation.value(), clazz); | |
} else {LOGGER.warn("annotation not present at {}", clazz.getName()); | |
} | |
} | |
private Class<?> getMetadata(String name) {return metadata.getOrDefault(name.toLowerCase(), Void.class); | |
} | |
} |
- CommandSuite 的结构器增加了 PingCommand、EchoCommand、QuitCommand、TimeCommand 四个 command;addCommand 办法将 factory.wrap(command) 的命令放入 commands 中
CommandWrapperFactory
resp-server-0.16.0/src/main/java/com/github/tonivade/resp/command/CommandWrapperFactory.java
public interface CommandWrapperFactory {RespCommand wrap(Object command); | |
} |
- CommandWrapperFactory 定义了 wrap 办法,将 command 包装为 RespCommand
DefaultCommandWrapperFactory
resp-server-0.16.0/src/main/java/com/github/tonivade/resp/command/DefaultCommandWrapperFactory.java
public class DefaultCommandWrapperFactory implements CommandWrapperFactory { | |
@Override | |
public RespCommand wrap(Object command) {if (command instanceof RespCommand) {return new CommandWrapper((RespCommand) command); | |
} | |
throw new IllegalArgumentException("must implements command interface"); | |
} | |
} |
- DefaultCommandWrapperFactory 实现了 CommandWrapperFactory 接口,其 wrap 办法应用 CommandWrapper 包装 RespCommand
CommandWrapper
resp-server-0.16.0/src/main/java/com/github/tonivade/resp/command/CommandWrapper.java
public class CommandWrapper implements RespCommand { | |
private int params; | |
private final RespCommand command; | |
public CommandWrapper(RespCommand command) { | |
this.command = command; | |
ParamLength length = command.getClass().getAnnotation(ParamLength.class); | |
if (length != null) {this.params = length.value(); | |
} | |
} | |
@Override | |
public RedisToken execute(Request request) {if (request.getLength() < params) {return error("ERR wrong number of arguments for'" + request.getCommand() + "'command"); | |
} | |
return command.execute(request); | |
} | |
} |
- CommandWrapper 会读取 ParamLength 注解,若读的到则将注解的 value 值赋值给 params,用于 execute 办法对 request 的参数长度进行校验
小结
RespCommand 定义了 execute 办法,接管 Request 参数,返回 RedisToken;CommandSuite 的结构器增加了 PingCommand、EchoCommand、QuitCommand、TimeCommand 四个 command;addCommand 办法将 factory.wrap(command) 的命令放入 commands 中;DefaultCommandWrapperFactory 实现了 CommandWrapperFactory 接口,其 wrap 办法应用 CommandWrapper 包装 RespCommand;CommandWrapper 会读取 ParamLength 注解,若读的到则将注解的 value 值赋值给 params,用于 execute 办法对 request 的参数长度进行校验
doc
- RespCommand