既有的HttpURLConnection存在许多问题java
<!--more-->react
在此以前,可使用如下工具做为Http客户端程序员
咱们来看一段HTTP Client的常规用法的样例 ——
执行GET请求,而后输出响应体(Response Body)。编程
HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://openjdk.java.net/")) .build(); client.sendAsync(request, asString()) .thenApply(HttpResponse::body) .thenAccept(System.out::println) .join();
通常使用JDK 11中的HttpClient的第一步是建立HttpClient对象并进行配置。json
HttpClient client = HttpClient.newBuilder() .version(Version.HTTP_2) .followRedirects(Redirect.SAME_PROTOCOL) .proxy(ProxySelector.of(new InetSocketAddress("www-proxy.com", 8080))) .authenticator(Authenticator.getDefault()) .build();
从HttpRequest的builder组建request服务器
HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://openjdk.java.net/")) .timeout(Duration.ofMinutes(1)) .header("Content-Type", "application/json") .POST(BodyPublisher.fromFile(Paths.get("file.json"))) .build()
同步发送API阻塞直到HttpResponse返回多线程
HttpResponse<String> response = client.send(request, BodyHandler.asString()); System.out.println(response.statusCode()); System.out.println(response.body());
client.sendAsync(request, BodyHandler.asString()) .thenApply(response -> { System.out.println(response.statusCode()); return response; } ) .thenApply(HttpResponse::body) .thenAccept(System.out::println);
※CompletableFuture是在java8中加入的,支持组合式异步编程并发
Java NIO为Java带来了非阻塞模型。app
假设如下代码是一个聊天应用服务器的一部分,该应用以Vert.x框架实现。
(Eclipse Vert.x is a tool-kit for building reactive applications on the JVM.)
向connectHandler方法输入一个Lambda表达式,每当有用户链接到聊天应用时,都会调用该Lambda表达式。这就是一个回调。
这种方式的好处是,应用没必要控制线程模型——Vert.x框架为咱们管理线程,打理好一切相关复杂性,程序员只考虑和回调就够了。框架
vertx.createServer() .connectHandler(socket -> { socket.dataHandler(new User(socket, this)); }).listen(10_000);
注意,这种设计里,不共享任何状态。对象之间经过向事件总线发送消息通讯,根本不须要在代码中添加锁或使用synchronized关键字。并发编程变得更加简单。
大量的回调会怎样?请看如下伪代码
(1)->{ (2)->{ (3)->{ (4)->{} } } }
大量回调会造成“末日金字塔”。
如何破解? 使用Future
Future1=(1)->{} Future2=(Future1.get())->{} Future3=(Future2.get())->{} Future4=(Future3.get())->{}
但这会形成本来指望的并行处理,变成了串行处理,带来了性能问题。
咱们真正须要的是将Future和回调联合起来使用。下面将要讲的CompletableFuture就是结合了Future和回调,其要点是组合不一样实例而无需担忧末日金字塔问题。
(new CompletableFuture()).thenCompose((1)->{}) .thenCompose((2)->{}) .thenCompose((3)->{}) .thenCompose((4)->{}) .join()
Reactive Streams是一个倡议,它提倡提供一种带有非阻塞背压的异步流处理的标准(Reactive Streams is an initiative to provide a standard for asynchronous stream processing with non-blocking back pressure)。
JDK 9中的java.util.concurrent.Flow中的概念,与Reactive Streams是一对一对等的。java.util.concurrent.Flow是Reactive Streams标准的实现之一。
public abstract class HttpRequest { ... public interface BodyPublisher extends Flow.Publisher<ByteBuffer> { ... } }
public abstract class HttpResponse<T> { ... public interface BodyHandler<T> { BodySubscriber<T> apply(int statusCode, HttpHeaders responseHeaders); } public interface BodySubscriber<T> extends Flow.Subscriber<List<ByteBuffer>> { ... } }