从一开始,抱歉英语不好,我正在努力。
我的目标是在vert.x中创建http方法。每种方法都包含一些步骤,这些步骤可以被其他步骤阻止。为了简化,一个步骤可以被另一个步骤完全阻止。
我决定创建一个AsyncMethodHandler,它在handle
方法调用内,创建AsyncStepHandlers的示例。方法处理程序还会创建一个步骤期货映射,并尝试创建一个组合处理程序以供他们加入。
这是代码AsyncMethodHandler
:
public abstract class AsyncMethodHandler<T extends BaseChannelResponse> implements Handler<RoutingContext> {
private static final String CONTENT_TYPE_JSON = "application/json; charset=utf-8";
private final List<Class<? extends AsyncStepHandler>> steplist;
private final HttpMethod methodType;
private final String endpointName;
private final HttpEndpointName endpoint;
private String responseEndpoint;
public AsyncMethodHandler(HttpEndpointName endpoint, String endpointName, HttpMethod methodType, List<Class<? extends AsyncStepHandler>> steplist) {
this.steplist = steplist;
this.endpoint = endpoint;
this.endpointName = endpointName;
this.methodType = methodType;
}
@Override
public void handle(RoutingContext event) {
try {
Map<Class<? extends AsyncStepHandler>, Future> mapOfExecution = new ConcurrentHashMap<>(steplist.size());
List<AsyncStepHandler> handlers = new ArrayList<>(steplist.size());
for (Class<? extends AsyncStepHandler> stepClass : this.steplist) {
AsyncStepHandler stepHandler = stepClass.getConstructor(RoutingContext.class).newInstance(event);
mapOfExecution.put(stepClass, stepHandler.getStepFuture());
handlers.add(stepHandler);
}
for (AsyncStepHandler stepHandler : handlers) {
stepHandler.before(mapOfExecution).setHandler(stepHandler.makeHandler(mapOfExecution));
}
CompositeFuture.join(new ArrayList<>(mapOfExecution.values())).setHandler(handleResult(event, mapOfExecution));
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
}
}
private Handler<AsyncResult<CompositeFuture>> handleResult(RoutingContext event, Map<Class<? extends AsyncStepHandler>, Future> mapOfExecution) {
return result -> {
if (result.succeeded()) {
succeeded(event.response(), generateResponse(mapOfExecution));
} else {
ChannelAPIException error = ChannelAPIException.createFrom(result.cause());
errored(event.response(), error.getCode(), error.getMessage());
}
};
}
protected abstract T generateResponse(Map<Class<? extends AsyncStepHandler>, Future> mapOfExecution);
private void errored(HttpServerResponse response, int code, String message) {
response.putHeader(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_JSON)
.setStatusCode(code)
.end(message);
CAPIMetricFactory.incBotResponseError(this.responseEndpoint, code);
}
private void succeeded(HttpServerResponse response, T result) {
response.putHeader(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_JSON)
.setStatusCode(200)
.end(Serializer.toPrettyJson(result));
CAPIMetricFactory.incBotResponse(this.responseEndpoint);
}
public String getEndpointName() {
return endpointName;
}
public HttpMethod getMethodType() {
return methodType;
}
public HttpEndpointName getEndpoint() {
return endpoint;
}
public void setResponseEndpoint(String responseEndpoint) {
this.responseEndpoint = responseEndpoint;
}
}
这是代码AsyncStepHandlers
:
public abstract class AsyncStepHandler<T> {
private final Future stepFuture;
private final RoutingContext context;
private final Class<? extends AsyncStepHandler> before;
public AsyncStepHandler(RoutingContext context) {
this(Future.future(), context, null);
}
public AsyncStepHandler(RoutingContext context, Class<? extends AsyncStepHandler> before) {
this(Future.future(), context, before);
}
private AsyncStepHandler(Future stepFuture, RoutingContext context, Class<? extends AsyncStepHandler> before) {
this.stepFuture = stepFuture;
this.context = context;
this.before = before;
}
public static <T> T getResultFromMap(Map<Class<? extends AsyncStepHandler>, Future> mapOfExecution, Class<? extends AsyncStepHandler> key) {
return (T) mapOfExecution.get(key).result();
}
public final Future getStepFuture() {
return stepFuture;
}
public RoutingContext getContext() {
return context;
}
public Buffer getContextBody() {
return context.getBody();
}
public String getContextBodyAsString() {
return context.getBodyAsString();
}
public Future before(Map<Class<? extends AsyncStepHandler>, Future> mapOfExecution) {
if (before != null) {
return mapOfExecution.get(before);
} else {
return Future.succeededFuture();
}
}
public abstract Future<T> execute(Map<Class<? extends AsyncStepHandler>, Future> mapOfExecution);
public Handler<AsyncResult> makeHandler(Map<Class<? extends AsyncStepHandler>, Future> mapOfExecution) {
return result -> {
if (result.succeeded()) {
this.execute(mapOfExecution).setHandler(this.finish());
} else {
stepFuture.fail(result.cause());
}
};
}
private Handler<AsyncResult<T>> finish() {
return result -> {
if (result.succeeded()) {
stepFuture.complete(result.result());
} else {
stepFuture.fail(result.cause());
}
};
}
}
因此,我尝试创建一些实际的方法和步骤。例如:
所以这是代码:
public class SimpleTestMethod extends AsyncMethodHandler<TestData> {
public SimpleTestMethod(String endpoint) {
super(
CHANNEL_API_SEND_TEXT,
endpoint,
POST,
new ArrayList<Class<? extends AsyncStepHandler>>(){{
add(ParametersStep.class);
}{
add(AuthorizationStep.class);
}{
add(ValidateStep.class);
}}
);
}
@Override
protected TestData generateResponse(Map<Class<? extends AsyncStepHandler>, Future> mapOfExecution) {
System.out.println("End");
SendMessageParameters response = (SendMessageParameters) mapOfExecution.get(ParametersStep.class).result();
ValidationResult validationResult = (ValidationResult) mapOfExecution.get(ValidateStep.class).result();
return new TestData(response.toString(),0l);
}
}
首先,例如步骤如下:
public class ParametersStep extends AsyncStepHandler<SendMessageParameters> {
public ParametersStep(RoutingContext context) {
super(context);
}
@Override
public Future<SendMessageParameters> execute(Map<Class<? extends AsyncStepHandler>, Future> mapOfExecution) {
System.out.println("ParametersStep");
SendMessageParameters parameters = parseJson(this.getContextBodyAsString(), SendMessageParameters.class);
return Future.succeededFuture(parameters);
}
}
可以执行。但是,如果我要添加一些等待步骤,那么该步骤之后的下一个将永远不会开始。
例如:
public class AuthorizationStep extends AsyncStepHandler<AuthResponse> {
public AuthorizationStep(RoutingContext context) {
super(context, ParametersStep.class);
}
@Override
public Future<AuthResponse> execute(Map<Class<? extends AsyncStepHandler>, Future> mapOfExecution) {
System.out.println("AuthorizationStep");
final Future<AuthResponse> authorization = Future.future();
SendMessageParameters parameters = getResultFromMap(mapOfExecution, ParametersStep.class);
AuthResponse response = new AuthResponse(new ChannelTokenData(0l,parameters.getToken(),true,0l,0l,null));
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
authorization.complete(response);
}
});
t.start();
return authorization;
}
}
然后将不会调用等待授权步骤结束的任何步骤。我阅读了官方文档,并试图找到有关此案的一些信息,但未成功。我尝试了不同的技术setHandler
,compose
,但得到的结果相同。
有人可以帮助我理解为什么下一步不会开始并解决此问题,因为下一部分是使用CompositeFuture =)
P.S .: 最有趣的是,例如,如果AuthorizationStep是3步方法中的第二步-执行将在第二步停止。但是如果我这样做:
@Override
public void handle(RoutingContext event) {
try {
Map<Class<? extends AsyncStepHandler>, Future> mapOfExecution = new ConcurrentHashMap<>(steplist.size());
List<AsyncStepHandler> handlers = new ArrayList<>(steplist.size());
CountDownLatch latch = new CountDownLatch(steplist.size());
for (Class<? extends AsyncStepHandler> stepClass : this.steplist) {
AsyncStepHandler stepHandler = stepClass.getConstructor(RoutingContext.class).newInstance(event);
mapOfExecution.put(stepClass, stepHandler.getStepFuture());
handlers.add(stepHandler);
stepHandler.setLatch(latch);
}
for (AsyncStepHandler stepHandler : handlers) {
stepHandler.before(mapOfExecution).setHandler(stepHandler.makeHandler(mapOfExecution));
}
latch.await();
CompositeFuture.join(new ArrayList<>(mapOfExecution.values())).setHandler(handleResult(event, mapOfExecution));
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
这在AsyncStepHandler中:
private Handler<AsyncResult<T>> finish() {
return result -> {
System.out.println("finish");
if (result.succeeded()) {
latch.countDown();
stepFuture.complete(result.result());
} else {
stepFuture.fail(result.cause());
}
};
}
一切都开始起作用。如果我添加倒计时闩锁,并在Composite将来加入之前添加await,那么一切都会好起来的。