前言
对于使用过vert.x的开发者而言,肯定接触到过callback hell。而vert.x的Future就是解决这个问题的一种方式.
官方实例:
Future.<Message<String>>future(f ->
vertx.eventBus().send("address1", "message", f)
).compose((msg) ->
Future.<Message<String>>future(f ->
vertx.eventBus().send("address2", msg.body(), f)
)
).compose((msg) ->
Future.<Message<String>>future(f ->
vertx.eventBus().send("address3", msg.body(), f)
)
).setHandler((res) -> {
if (res.failed()) {
//deal with exception
return;
}
//deal with the result
});
本文后续分析所用实例:
public static void main(String[] args) throws InterruptedException {
Vertx vertx=Vertx.vertx();
//创建future
Future<Buffer> future = Future.future();
future.setHandler(as -> {
if(as.succeeded()){
System.out.println("read success");
System.out.println(as.result().toString());
}
});
String filePath = "./Downloads/abc.txt";
FileSystem fileSystem = vertx.fileSystem();
fileSystem.createFile(filePath, as -> {
fileSystem.readFile(filePath, future);
});
}
示例调用过程分析
createFile方法
public FileSystem createFile(String path, Handler<AsyncResult<Void>> handler) {
createFileInternal(path, handler).run();
return this;
}
private BlockingAction<Void> createFileInternal(String path, Handler<AsyncResult<Void>> handler) {
return createFileInternal(path, null, handler);
}
protected BlockingAction<Void> createFileInternal(String p, String perms, Handler<AsyncResult<Void>> handler) {
Objects.requireNonNull(p);
FileAttribute<?> attrs = perms == null ? null : PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString(perms));
return new BlockingAction<Void>(handler) {
public Void perform() {
try {
Path target = vertx.resolveFile(p).toPath();
if (attrs != null) {
Files.createFile(target, attrs);
} else {
Files.createFile(target);
}
} catch (IOException e) {
throw new FileSystemException(e);
}
return null;
}
};
}
创建一个读取文件的动作类(实现了Handler<Future>),由于这里分析的是Future,至于具体如何createFile的这里不做分析
BlockingAction(在FileSystemImpl类中)
protected abstract class BlockingAction<T> implements Handler<Future<T>> {
private final Handler<AsyncResult<T>> handler;
protected final ContextInternal context;
public BlockingAction(Handler<AsyncResult<T>> handler) {
this.handler = handler;
this.context = vertx.getOrCreateContext();
}
/**
* Run the blocking action using a thread from the worker pool.
*/
public void run() {
context.executeBlockingInternal(this, handler);
}
//这可以看到,他会在完成后主动调用fut的complete方法(complete具体实现会在后续分析)
@Override
public void handle(Future<T> fut) {
try {
T result = perform();
fut.complete(result);
} catch (Exception e) {
fut.fail(e);
}
}
public abstract T perform();
}
BlockingAction.run方法
public void run() {
context.executeBlockingInternal(this, handler);
}
@Override
public <T> void executeBlockingInternal(Handler<Future<T>> action, Handler<AsyncResult<T>> resultHandler) {
executeBlocking(action, resultHandler, internalBlockingPool.executor(), internalOrderedTasks, internalBlockingPool.metrics());
}
<T> void executeBlocking(Handler<Future<T>> blockingCodeHandler,
Handler<AsyncResult<T>> resultHandler,
Executor exec, TaskQueue queue, PoolMetrics metrics) {
Object queueMetric = metrics != null ? metrics.submitted() : null;
try {
//新建一个线程来执行读取文件的任务
Runnable command = () -> {
VertxThread current = (VertxThread) Thread.currentThread();
Object execMetric = null;
if (metrics != null) {
execMetric = metrics.begin(queueMetric);
}
if (!DISABLE_TIMINGS) {
current.executeStart();
}
//创建一个Future来接收结果(在这个Futue中调用我在Main中创建的Future)
Future<T> res = Future.future();
try {
ContextImpl.setContext(this);
//调用BlockingAction的handler
blockingCodeHandler.handle(res);
} catch (Throwable e) {
res.tryFail(e);
} finally {
if (!DISABLE_TIMINGS) {
current.executeEnd();
}
}
if (metrics != null) {
metrics.end(execMetric, res.succeeded());
}
//这就是上边可以调用到我创建future的原因
if (resultHandler != null) {
res.setHandler(ar -> runOnContext(v -> resultHandler.handle(ar)));
}
};
//在vertx中执行这个Runnable,这里如何实现的异步,就涉及到了vertx的线程模型以及netty的原理分析,超过了这篇文章的范围,不再分析
if (queue != null) {
queue.execute(command, exec);
} else {
exec.execute(command);
}
} catch (RejectedExecutionException e) {
// Pool is already shut down
if (metrics != null) {
metrics.rejected(queueMetric);
}
throw e;
}
}
这就是这个示例整个的流程,下面就分析下Future的具体实现
Future实现解析
Future继承了AsyncResult接口,所以future本身可以携带异步结果的同时也可以是AsyncResult异步结果的携带者。
Future也继承了Handler<AsyncResult>,所以很多调用处需要Handler的地方,也可以直接传Future
Vert.x本身最常用的实现类是FutureImpl,所以后续主要分析的就是FutureImpl(至于如何使用FutureFactory创建的,感兴趣的请自行查看源码)
FutureImpl中的变量:
- failed,true:这是失败的异步结果。此时throwable不为空。
- succeeded,true:这是成功的异步结果。如果有设置结果的话,result不为空。
- handler:真正的异步结果处理器,setHandler方法传入的handler保存在这里。
- result:结果属性。
- throwable:异常结果属性
complete/tryComplete方法
@Override
public void complete(T result) {
if (!tryComplete(result)) {
throw new IllegalStateException("Result is already complete: " + (succeeded ? "succeeded" : "failed"));
}
}
@Override
public boolean tryComplete(T result) {
Handler<AsyncResult<T>> h;
synchronized (this) {
if (succeeded || failed) {
return false;
}
this.result = result;
succeeded = true;
h = handler;
handler = null;
}
if (h != null) {
h.handle(this);
}
return true;
}
complete方法委托给tryComplete方法来实现。如果tryComplete方法返回false,则说明此异步结果已经完成了,进入if分支,抛出异常。由此可以看出future的最终状态确定下来,就不再改变。
接下来看tryComplete方法。很简单。就是把结果赋值给result。设置到succeeded为true代表当前AsyncResult已经完成。如果当前已经设置了handler那么就触发该handler。(大多数情况,这是已经设置到handler)。failed方法此时类似。
setHandler方法
/**
* Set a handler for the result. It will get called when it's complete
*/
public Future<T> setHandler(Handler<AsyncResult<T>> handler) {
boolean callHandler;
synchronized (this) {
callHandler = isComplete();
if (!callHandler) {
this.handler = handler;
}
}
if (callHandler) {
handler.handle(this);
}
return this;
}
public synchronized boolean isComplete() {
return failed || succeeded;
}
sethandler方法也很简单,就是把handler赋值给属性handler。如果当前future的AsyncResult已经完成,那么触发handler。
handle方法
public void handle(AsyncResult<T> asyncResult) {
if (asyncResult.succeeded()) {
complete(asyncResult.result());
} else {
fail(asyncResult.cause());
}
}
很简单,就是调用complete方法和failed方法即可。
compose方法
default <U> Future<U> compose(Function<T, Future<U>> mapper) {
if (mapper == null) {
throw new NullPointerException();
}
//先创建好future,然后下面返回这个新创建的future。
Future<U> ret = Future.future();
//给当前future设置handler。这个handler在将来某个时刻执行。
setHandler(ar -> {
//这个代码块的代码跟外面的代码执行时机不同。
//1. 外面的ret,将在当前future的compose方法调用时执行并返回。
//2. 在下一个compose方法或者setHandler方法为ret设置handler。
// 将来某一时刻到了。执行了这个代码块。 到了此时,当前future已经完成,
//并且执行handler中的handle方法。
if (ar.succeeded()) {
Future<U> apply;
try {
//3. 获取future中的异步结果。调用compose方法的传入mapper这个functionalInterface
//4.mapper返回下一个异步操作future(apply)。
apply = mapper.apply(ar.result());
} catch (Throwable e) {
//执行mapper失败,直接设置ret的异常结果。以完成ret这个future,且触发handler的执行
ret.fail(e);
return;
}
//5.为apply设置handler。(此时的ret已经完成handler的设置,执行时机不同)
//6. 这个apply future又会将在未来某一时刻执行。注意:在未来某一时刻。执行时机不同。
//7. 当apply完成时,调用handler。apply自身作为异步结果(AsyncResult),
//调用ret(此时ret作为Handler)
apply.setHandler(ret);
} else {
//如果当前的函数是失败状态的,直接设置ret的异常结果。
//以完成ret这个future,且触发handler的执行
ret.fail(ar.cause());
}
});
return ret;
}
map方法和compose方法类似(更简单),这里就不进行分析了