您现在的位置是:亿华云 > 应用开发

Java11新特性-效能翻倍的HttpClient

亿华云2025-10-03 06:26:29【应用开发】6人已围观

简介古老的背景从JDK1.1开始,JDK中就有HttpURLConnection来提供了网络连接的能力,但是由于实现的比较古早,其有很多的局限性。比如HttpURLConnection是通过底层提供的so

古老的新特性效背景

从JDK1.1开始,JDK中就有HttpURLConnection来提供了网络连接的新特性效能力,但是新特性效由于实现的比较古早,其有很多的新特性效局限性。比如HttpURLConnection是新特性效通过底层提供的socket连接来进行通信,而每一个HttpURLConnection实例只能发送一个请求,新特性效之后只能通过close()释放请求的新特性效网络资源,或在持久化连接时用disconnect()来关闭关闭底层socket。新特性效而其基类URLConnection是新特性效为了支持很多协议而设计的,但诸如FTP这种协议已经不咋用了。新特性效

HttpURLConnection并不是新特性效不能使用,由于不需要依赖,新特性效在一些demo项目的新特性效时候也会偶尔拿来用。但HttpURLConnection本身已经太过古早,新特性效并且很难说HttpURLConnection能够胜任包含各种鉴权信息、新特性效各种COOKIE信息的访问请求。

Java11新特性-效能翻倍的HttpClient

针对这种情况网络上各种大神提供了更多高级的封装,比较流行的有Apache的HttpClient、站群服务器Okhttp Client、Spring Cloud Feign之类的。这些封装提供了更丰富的资源与更便捷的封装,也支持了更高级功能如HTTP/2协议、异步请求等。

Java11新特性-效能翻倍的HttpClient

不过到了JDK9的时候,Java提供了一个新的Http请求工具HttpClient,经过了JDK10的再次预览,最终在JAVA11中作为正式功能提供使用,同时也完全替换了仅有阻塞模式的HttpURLConnection。

Java11新特性-效能翻倍的HttpClient

HttpClient简介

作为JDK11中正式推出的新Http连接器,支持的功能还是比较新的,主要的特性有:

完整支持HTTP 2.0 或者HTTP 1.1支持 HTTPS/TLS有简单的阻塞使用方法支持异步发送,异步时间通知支持WebSocket支持响应式流

HTTP2.0其他的客户端也能支持,而HttpClient使用CompletableFuture作为异步的返回数据。WebSocket的支持则是HttpClient的服务器租用优势。响应式流的支持是HttpClient的一大优势。

而HttpClient中的NIO模型、函数式编程、CompletableFuture异步回调、响应式流让HttpClient拥有极强的并发处理能力,所以其性能极高,而内存占用则更少。

HttpClient的主要类有:

java.net.http.HttpClientjava.net.http.HttpRequestjava.net.http.HttpResponsejava.net.http.WebSocket(本文就不介绍这个了)

细节会在后文介绍,但是WebSocket用的比较少,本文就略过了。

核心使用

HttpClient 的核心类主要就是 HttpClient、HttpRequest以及HttpResponse,它们都是位于java.net.http 包下,接下来对他们进行一下介绍。

HttpClient

HttpClient类是最核心的类,它支持使用建造者模式进行复杂对象的构建,主要的参数有:

Http 协议的香港云服务器版本 (HTTP 1.1 或者 HTTP 2.0),默认是 2.0。是否遵从服务器发出的重定向连接超时时间代理认证//可以用参数调整

HttpClient client = HttpClient.newBuilder()

.version(Version.HTTP_1_1)

.followRedirects(Redirect.NORMAL)

.connectTimeout(Duration.ofSeconds(20))

.proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 8080)))

.authenticator(Authenticator.getDefault())

.build();

//也可以直接全部默认的便捷创建

HttpClient clientSimple = HttpClient.newHttpClient();

当创建了HttpClient实例后,可以通过其发送多条请求,不用重复创建。

HttpRequest

HttpRequest 是用语描述请求体的类,也支持通过建造者模式构建复杂对象,主要的参数有:

请求地址请求方法:GET,POST,DELETE 等(默认是GET)请求体 (按需设置,例如 GET 不用 body,但是 POST 要设置)请求超时时间(默认)请求头//使用参数组合进行对象构建,读取文件作为请求体

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 是一个不可变类,可以被多次发送。

HttpResponse

HttpResponse没有提供外部可以创建的实现类,它是一个接口,从client的返回值中创建获得。接口中的主要方法为:

public interface HttpResponse{

public int statusCode();

public HttpRequest request();

public Optional> previousResponse();

public HttpHeaders headers();

public T body();

public URI uri();

public OptionalsslSession();

public HttpClient.Version version();

}

HttpResponse的返回内容与常识一致,这里就不展开介绍了。

信息发送

HttpClient中可以使用同步发送或者异步发送。

同步 send()

同步发送后,请求会一直阻塞到收到response为止。

final HttpResponsesend = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

System.out.println(send.body());

其中 send的第二个参数是通过HttpResponse.BodyHandlers的静态工厂来返回一个可以将 response 转换为目标类型T的处理器(handler),本例子中的类型是String。

HttpResponse.BodyHandlers.ofString()的实现方法为:

public static BodyHandlerofString() {

return (responseInfo) -> BodySubscribers.ofString(charsetFrom(responseInfo.headers()));

}

其中,BodySubscribers.ofString() 的方法实现是:

public static BodySubscriberofString(Charset charset) {

Objects.requireNonNull(charset);

return new ResponseSubscribers.ByteArraySubscriber<>(

bytes -> new String(bytes, charset)

);

}

可以看到最终是返回了一个ResponseSubscribers ,而Subscribers则是我们之前《JDK9响应式编程》中讨论过的订阅者。这个构造方法的入参Function定义了订阅者中的finisher属性,而这个属性将在响应式流完成订阅的时在onComplete()`方法中调用。

异步 sendAsync()

异步请求发送之后,会立刻返回 CompletableFuture,然后可以使用CompletableFuture中的方法来设置异步处理器。

client.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())

.thenApply(HttpResponse::body)

.thenAccept(System.out::println)

.join();

而就如同JDK中响应式流中发布者的submit()方法与offer()方法一样,HttpClient中的send()方法知识sendAsync方法的特例,在send()方法中是先调用sendAsync()方法,然后直接阻塞等待响应结束再返回,部分核心代码为:

@Override

public HttpResponse

send(HttpRequest req, BodyHandlerresponseHandler)

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;

}

...响应式流

HttpClient 作为 Request 的发布者 (publisher),将 Request 发布到服务器,作为 Response 的订阅者 (subscriber),从服务器接收 Response。而上文中我们在send()的部分发现,调用链的最底端返回的是一个ResponseSubscribers订阅者。

当然,就如同

HttpResponse.BodyHandlers.ofString(),HttpClient默认提供了一系列的默认订阅者,用语处理数据的转换:

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的时候我们也可以自己创建一个实现了Flow.Subscriber>接口的订阅者,用于消费数据。响应式流完整的简单的例子如下:

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.BodySubscribersubscriber = 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;

Listresponse = 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(Listitem) {

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客户端。其底层基于响应式流,通过上层封装还提供了异步信息发送、同步信息发送,以及其他完成的HTTP协议内容。在进行响应式编程的方面,HttpClient也是一个十分优秀的参照目标。

很赞哦!(6462)