
com.github.df.restypass.command.DefaultRestyCommand Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of resty-pass Show documentation
Show all versions of resty-pass Show documentation
High-Performance Restful Client Library
package com.github.df.restypass.command;
import com.github.df.restypass.cb.CircuitBreaker;
import com.github.df.restypass.enums.RestyCommandStatus;
import com.github.df.restypass.exception.execute.RestyException;
import com.github.df.restypass.lb.server.ServerInstance;
import com.github.df.restypass.util.StringBuilderFactory;
import org.asynchttpclient.*;
import org.asynchttpclient.uri.Uri;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.concurrent.*;
/**
* 默认Resty请求命令
* 封装请求内容,实现请求过程
* Created by darrenfu on 17-6-20.
*/
public class DefaultRestyCommand implements RestyCommand {
private static final Logger log = LoggerFactory.getLogger(DefaultRestyCommand.class);
/**
* request 模板
*/
private RestyRequestTemplate requestTemplate;
/**
* command请求路径 [requestTemplate]
* 如果有PathVariable,此处的path获取的是原始路径(如:/find/{name}),而不是参数替换后的路径
*/
private String path;
/**
* Get or Post [requestTemplate]
*/
private String httpMethod;
/**
* Class
*/
private Class serviceClz;
/**
* Method
*/
private Method serviceMethod;
/**
* 返回类型
*/
private Type returnType;
/**
* 方法参数列表
*/
private Object[] args;
/**
* 上下文context
*/
private RestyCommandContext context;
/**
* command 配置
*/
private RestyCommandConfig restyCommandConfig;
/**
* 服务名称 [restyCommandConfig]
*/
private String serviceName;
/**
* 状态
*/
private RestyCommandStatus status;
/**
* 导致Command失败的异常
*/
private RestyException exception;
/**
* 向服务请求的request
*/
private Request request;
/**
* Uri
*/
private Uri uri;
/**
* 使用的断路器
*/
private CircuitBreaker circuitBreaker;
/**
* command执行访问的服务实例(最后一次)
*/
private ServerInstance instance;
/**
* 是否是异步命令-基于返回值future
* 示例接口:
* Future getUser(String userId);
**/
private boolean asyncFutureReturn;
/**
* 是否是异步命令-基于请求参数future
* 示例接口:User getUser(String userId, RestyFuture);
*/
private boolean asyncFutureArg;
public DefaultRestyCommand(Class serviceClz,
Method serviceMethod,
Type returnTyp,
Object[] args,
RestyCommandContext context) {
this.serviceClz = serviceClz;
this.serviceMethod = serviceMethod;
this.returnType = returnTyp;
this.args = args;
this.context = context;
this.status = RestyCommandStatus.INIT;
if (context.getCommandProperties(serviceMethod) == null) {
throw new IllegalArgumentException("缺少CommandProperties,无法初始化RestyCommand");
}
this.restyCommandConfig = context.getCommandProperties(serviceMethod);
this.serviceName = restyCommandConfig.getServiceName();
this.requestTemplate = context.getRequestTemplate(serviceMethod);
this.httpMethod = requestTemplate.getHttpMethod();
this.path = requestTemplate.getPath();
isAsyncCommand();
}
@Override
public String getPath() {
return this.path;
}
@Override
public String getHttpMethod() {
return this.httpMethod;
}
@Override
public String getServiceName() {
return this.serviceName;
}
@Override
public Method getServiceMethod() {
return this.serviceMethod;
}
@Override
public Type getReturnType() {
return this.returnType;
}
@Override
public Object[] getArgs() {
return this.args;
}
@Override
public RestyCommandConfig getRestyCommandConfig() {
return this.restyCommandConfig;
}
@Override
public Uri getUri(ServerInstance serverInstance) {
if (uri == null) {
uri = createUri(serverInstance);
}
return uri;
}
private Uri createUri(ServerInstance serverInstance) {
return new Uri(serverInstance.getIsHttps() ? HTTPS : HTTP,
null,
serverInstance.getHost(),
serverInstance.getPort(),
requestTemplate.getRequestPath(args),
requestTemplate.getQueryString(args));
}
@Override
public RestyRequestTemplate getRequestTemplate() {
return this.requestTemplate;
}
@Override
public boolean isAsyncReturn() {
return this.asyncFutureReturn;
}
@Override
public boolean isAsyncArg() {
return this.asyncFutureArg;
}
/**
* 是否是异步请求
*
* @return 是异步:true, 不是异步请求:false
*/
private boolean isAsyncCommand() {
Type returnType = this.getReturnType();
this.asyncFutureReturn = false;
this.asyncFutureArg = false;
if (returnType instanceof ParameterizedTypeImpl) {
//返回类型是Future
ParameterizedTypeImpl returnParameterType = (ParameterizedTypeImpl) returnType;
if ((returnParameterType.getRawType() == Future.class || returnParameterType.getRawType() == RestyFuture.class)
&& returnParameterType.getActualTypeArguments() != null
&& returnParameterType.getActualTypeArguments().length > 0) {
//替换return type: Future -> User
this.returnType = returnParameterType.getActualTypeArguments()[0];
this.asyncFutureReturn = true;
return true;
}
}
RestyFuture futureArg = getFutureArg(this);
if (futureArg != null) {
/**
* Future类型出参
* command执行的时候处理此类异步,将执行结果future放入futureArg中
* @see DefaultRestyCommand#start
*/
this.asyncFutureArg = true;
return true;
}
return false;
}
private RestyFuture getFutureArg(RestyCommand restyCommand) {
if (restyCommand.getArgs() != null && restyCommand.getArgs().length > 0) {
for (Object arg : restyCommand.getArgs()) {
if (arg != null && arg instanceof RestyFuture) {
return (RestyFuture) arg;
}
}
}
return null;
}
@Override
public RestyCommandStatus getStatus() {
return this.status;
}
@Override
public RestyCommand ready(CircuitBreaker cb) {
this.circuitBreaker = cb;
this.status = RestyCommandStatus.READY;
return this;
}
@Override
public RestyFuture start(ServerInstance instance) {
if (this.instance != null && !this.instance.equals(instance.getInstanceId())) {
this.uri = this.createUri(instance);
}
this.status = RestyCommandStatus.STARTED;
this.instance = instance;
AsyncHttpClient httpClient = context.getHttpClient(this.getServiceName());
BoundRequestBuilder requestBuilder = new BoundRequestBuilder(httpClient,
httpMethod,
true);
requestBuilder.setUri(this.getUri(instance));
requestBuilder.setSingleHeaders(requestTemplate.getRequestHeaders(args));
requestBuilder.setBody(requestTemplate.getBody(args));
this.request = requestBuilder.build();
ListenableFuture future;
RestyFuture restyFuture = new RestyFuture();
restyFuture.setRestyCommand(this);
try {
future = requestBuilder.execute();
} catch (Exception e) {
future = new ErrorFuture<>(e);
}
restyFuture.setFuture(future);
if (log.isDebugEnabled()) {
log.debug("Request:{}", request);
}
if (this.asyncFutureArg) {
RestyFuture futureArg = getFutureArg(this);
futureArg.setFuture(future);
futureArg.setRestyCommand(this);
}
return restyFuture;
}
@Override
public String getInstanceId() {
if (this.instance == null) {
throw new RuntimeException("instance is null");
}
return this.instance.getInstanceId();
}
@Override
public void success() {
this.status = RestyCommandStatus.SUCCESS;
if (log.isDebugEnabled()) {
log.debug("请求成功:{} @ {}", this.getPath(), this.instance);
}
this.emit(circuitBreaker.getEventKey(), this);
}
@Override
public void failed(RestyException restyException) {
this.exception = restyException;
this.status = RestyCommandStatus.FAILED;
if (log.isWarnEnabled()) {
log.warn("请求失败:{}@{}: {}", this.getPath(), this.instance, Arrays.toString(this.args));
}
this.emit(circuitBreaker.getEventKey(), this);
throw exception;
}
@Override
public RestyException getFailException() {
return this.exception;
}
@Override
public String toString() {
return "DefaultRestyCommand{" +
"path='" + path + '\'' +
", httpMethod='" + httpMethod + '\'' +
", serviceClz=" + serviceClz +
", serviceMethod=" + serviceMethod +
", args=" + Arrays.toString(args) +
", serviceName='" + serviceName + '\'' +
", status=" + status +
", exception=" + exception +
", uri=" + uri +
'}';
}
static class SingletonAsyncErrorHandler extends AsyncCompletionHandlerBase {
static SingletonAsyncErrorHandler handler = new SingletonAsyncErrorHandler();
SingletonAsyncErrorHandler() {
}
@Override
public void onThrowable(Throwable t) {
// do nothing
}
}
class ErrorFuture implements ListenableFuture {
private final ExecutionException e;
public ErrorFuture(Throwable t) {
e = new ExecutionException(t);
}
public ErrorFuture(String message, Throwable t) {
e = new ExecutionException(message, t);
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return true;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return true;
}
@Override
public T get() throws RestyException {
throw new RestyException(e);
}
@Override
public T get(long timeout, TimeUnit unit) throws RestyException {
throw new RestyException(e);
}
@Override
public void done() {
}
@Override
public void abort(Throwable t) {
}
@Override
public void touch() {
}
@Override
public ListenableFuture addListener(Runnable listener, Executor exec) {
if (exec != null) {
exec.execute(listener);
} else {
listener.run();
}
return this;
}
@Override
public CompletableFuture toCompletableFuture() {
CompletableFuture future = new CompletableFuture<>();
future.completeExceptionally(e);
return future;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy