日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Java11新特性-效能翻倍的HttpClient

古老的背景

HttpURLConnection并不是不能使用,由于不需要依賴,在一些demo項(xiàng)目的時(shí)候也會偶爾拿來用。但HttpURLConnection本身已經(jīng)太過古早,并且很難說HttpURLConnection能夠勝任包含各種鑒權(quán)信息、各種COOKIE信息的訪問請求。

針對這種情況網(wǎng)絡(luò)上各種大神提供了更多高級的封裝,比較流行的有Apache的HttpClient、Okhttp Client、Spring Cloud Feign之類的。這些封裝提供了更豐富的資源與更便捷的封裝,也支持了更高級功能如HTTP/2協(xié)議、異步請求等。

不過到了JDK9的時(shí)候,Java提供了一個(gè)新的Http請求工具HttpClient,經(jīng)過了JDK10的再次預(yù)覽,最終在JAVA11中作為正式功能提供使用,同時(shí)也完全替換了僅有阻塞模式的HttpURLConnection。

HttpClient簡介

作為JDK11中正式推出的新Http連接器,支持的功能還是比較新的,主要的特性有:

  • 完整支持HTTP 2.0 或者HTTP 1.1
  • 支持 HTTPS/TLS
  • 有簡單的阻塞使用方法
  • 支持異步發(fā)送,異步時(shí)間通知
  • 支持WebSocket
  • 支持響應(yīng)式流

HTTP2.0其他的客戶端也能支持,而HttpClient使用CompletableFuture作為異步的返回?cái)?shù)據(jù)。WebSocket的支持則是HttpClient的優(yōu)勢。響應(yīng)式流的支持是HttpClient的一大優(yōu)勢。

而HttpClient中的NIO模型、函數(shù)式編程、CompletableFuture異步回調(diào)、響應(yīng)式流讓HttpClient擁有極強(qiáng)的并發(fā)處理能力,所以其性能極高,而內(nèi)存占用則更少。

HttpClient的主要類有:

  • java.net.http.HttpClient
  • java.net.http.HttpRequest
  • java.net.http.HttpResponse
  • java.net.http.WebSocket(本文就不介紹這個(gè)了)

細(xì)節(jié)會在后文介紹,但是WebSocket用的比較少,本文就略過了。

核心使用

HttpClient 的核心類主要就是 HttpClient、HttpRequest以及HttpResponse,它們都是位于java.net.http 包下,接下來對他們進(jìn)行一下介紹。

HttpClient

HttpClient類是最核心的類,它支持使用建造者模式進(jìn)行復(fù)雜對象的構(gòu)建,主要的參數(shù)有:

  • Http 協(xié)議的版本 (HTTP 1.1 或者 HTTP 2.0),默認(rèn)是 2.0。
  • 是否遵從服務(wù)器發(fā)出的重定向
  • 連接超時(shí)時(shí)間
  • 代理
  • 認(rèn)證
//可以用參數(shù)調(diào)整
HttpClient client = HttpClient.newBuilder()
.version(Version.HTTP_1_1)
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.proxy(ProxySelector.of(new InetSocketAddress("proxy.cdxwcx.com", 8080)))
.authenticator(Authenticator.getDefault())
.build();

//也可以直接全部默認(rèn)的便捷創(chuàng)建
HttpClient clientSimple = HttpClient.newHttpClient();

當(dāng)創(chuàng)建了HttpClient實(shí)例后,可以通過其發(fā)送多條請求,不用重復(fù)創(chuàng)建。

HttpRequest

HttpRequest 是用語描述請求體的類,也支持通過建造者模式構(gòu)建復(fù)雜對象,主要的參數(shù)有:

  • 請求地址
  • 請求方法:GET,POST,DELETE 等(默認(rèn)是GET)
  • 請求體 (按需設(shè)置,例如 GET 不用 body,但是 POST 要設(shè)置)
  • 請求超時(shí)時(shí)間(默認(rèn))
  • 請求頭
//使用參數(shù)組合進(jìn)行對象構(gòu)建,讀取文件作為請求體
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://www.baidu.com"))
.timeout(Duration.ofSeconds(20))
.header("Content-type","application/json")
.POST(HttpRequest.BodyPublishers.ofFile(Paths.get("data.json")))
.build();
//直接GET訪問
HttpRequest requestSimple = HttpRequest.newBuilder(URI.create("http://www.baidu.com")).build();

HttpRequest 是一個(gè)不可變類,可以被多次發(fā)送。

HttpResponse

HttpResponse沒有提供外部可以創(chuàng)建的實(shí)現(xiàn)類,它是一個(gè)接口,從client的返回值中創(chuàng)建獲得。接口中的主要方法為:

public interface HttpResponse {
public int statusCode();
public HttpRequest request();
public Optional> previousResponse();
public HttpHeaders headers();
public T body();
public URI uri();
public Optional sslSession();
public HttpClient.Version version();
}

HttpResponse的返回內(nèi)容與常識一致,這里就不展開介紹了。

信息發(fā)送

HttpClient中可以使用同步發(fā)送或者異步發(fā)送。

同步 send()

同步發(fā)送后,請求會一直阻塞到收到response為止。

final HttpResponse send = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());
System.out.println(send.body());

其中 send的第二個(gè)參數(shù)是通過HttpResponse.BodyHandlers的靜態(tài)工廠來返回一個(gè)可以將 response 轉(zhuǎn)換為目標(biāo)類型T的處理器(handler),本例子中的類型是String。

HttpResponse.BodyHandlers.ofString()的實(shí)現(xiàn)方法為:

public static BodyHandler ofString() {
return (responseInfo) -> BodySubscribers.ofString(charsetFrom(responseInfo.headers()));
}

其中,BodySubscribers.ofString() 的方法實(shí)現(xiàn)是:

public static BodySubscriber ofString(Charset charset) {
Objects.requireNonNull(charset);
return new ResponseSubscribers.ByteArraySubscriber<>(
bytes -> new String(bytes, charset)
);
}

可以看到最終是返回了一個(gè)ResponseSubscribers ,而Subscribers則是我們之前《JDK9響應(yīng)式編程》中討論過的訂閱者。這個(gè)構(gòu)造方法的入?yún)unction定義了訂閱者中的finisher屬性,而這個(gè)屬性將在響應(yīng)式流完成訂閱的時(shí)在onComplete()`方法中調(diào)用。

異步 sendAsync()

異步請求發(fā)送之后,會立刻返回 CompletableFuture,然后可以使用CompletableFuture中的方法來設(shè)置異步處理器。

client.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();

而就如同JDK中響應(yīng)式流中發(fā)布者的submit()方法與offer()方法一樣,HttpClient中的send()方法知識sendAsync方法的特例,在send()方法中是先調(diào)用sendAsync()方法,然后直接阻塞等待響應(yīng)結(jié)束再返回,部分核心代碼為:

 @Override
public HttpResponse
send(HttpRequest req, BodyHandler responseHandler)
throws IOException, InterruptedException
{
CompletableFuture> cf = null;

// if the thread is already interrupted no need to go further.
// cf.get() would throw anyway.
if (Thread.interrupted()) throw new InterruptedException();
try {
cf = sendAsync(req, responseHandler, null, null);
return cf.get();
} catch (InterruptedException ie) {
if (cf != null )
cf.cancel(true);
throw ie;
}
...

響應(yīng)式流

HttpClient 作為 Request 的發(fā)布者 (publisher),將 Request 發(fā)布到服務(wù)器,作為 Response 的訂閱者 (subscriber),從服務(wù)器接收 Response。而上文中我們在send()的部分發(fā)現(xiàn),調(diào)用鏈的最底端返回的是一個(gè)ResponseSubscribers訂閱者。

當(dāng)然,就如同

HttpResponse.BodyHandlers.ofString(),HttpClient默認(rèn)提供了一系列的默認(rèn)訂閱者,用語處理數(shù)據(jù)的轉(zhuǎn)換:

HttpRequest.BodyPublishers::ofByteArray(byte[])
HttpRequest.BodyPublishers::ofByteArrays(Iterable)
HttpRequest.BodyPublishers::ofFile(Path)
HttpRequest.BodyPublishers::ofString(String)
HttpRequest.BodyPublishers::ofInputStream(Supplier)

HttpResponse.BodyHandlers::ofByteArray()
HttpResponse.BodyHandlers::ofString()
HttpResponse.BodyHandlers::ofFile(Path)
HttpResponse.BodyHandlers::discarding()

所以在HttpClient的時(shí)候我們也可以自己創(chuàng)建一個(gè)實(shí)現(xiàn)了Flow.Subscriber>接口的訂閱者,用于消費(fèi)數(shù)據(jù)。響應(yīng)式流完整的簡單的例子如下:

public class HttpClientTest {

public static void main(String[] args) throws IOException, InterruptedException {
final HttpClient client = HttpClient.newHttpClient();
final HttpRequest httpRequest = HttpRequest.newBuilder(URI.create("http://www.baidu.com")).build();

HttpResponse.BodySubscriber subscriber = HttpResponse.BodySubscribers.fromSubscriber(new StringSubscriber(),StringSubscriber::getBody);
client.sendAsync(httpRequest,responseInfo -> subscriber)
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
}

static class StringSubscriber implements Flow.Subscriber>{
Flow.Subscription subscription;
List response = new ArrayList<>();
String body;
public String getBody(){
return body;
}

@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
subscription.request(1);
}

@Override
public void onNext(List item) {
response.addAll(item);
subscription.request(1);
}

@Override
public void onError(Throwable throwable) {
System.err.println(throwable);
}

@Override
public void onComplete() {
byte[] data = new byte[response.stream().mapToInt(ByteBuffer::remaining).sum()];
int offset = 0;
for(ByteBuffer buffer:response){
int remain = buffer.remaining();
buffer.get(data,offset,remain);
offset += remain;
}
body = new String(data);
}
}
}

最后

HttpClient是JDK11正式上線的高性能Http客戶端。其底層基于響應(yīng)式流,通過上層封裝還提供了異步信息發(fā)送、同步信息發(fā)送,以及其他完成的HTTP協(xié)議內(nèi)容。在進(jìn)行響應(yīng)式編程的方面,HttpClient也是一個(gè)十分優(yōu)秀的參照目標(biāo)。


網(wǎng)站名稱:Java11新特性-效能翻倍的HttpClient
鏈接分享:http://www.dlmjj.cn/article/dhdipeh.html