HttpClient 简介

java.net.http.HttpClient 是 jdk11 中正式启用的一个 http 工具类(其实早在 jdk9 的时候就已经存在了,只是处于孵化期),官方寓意为想要取代 HttpURLConnection 和 Apache HttpClient 等比较古老的开发工具。

新增的 HttpClient 截止到目前(2019年3月)为止其实网络资料还比较少,笔者只是根据一些博文和官方 Demo 自己摸索了一下,做了下总结。

由于是 jdk11 中才正式使用的工具类,距离开发者还很遥远,所以对于源码笔者暂不打算深挖,浅浅的理解怎么使用就行

一、HttpClient在 Apache HttpClient 中,一般会创建一个 HttpClient 对象来作为门面。java.net.http.HttpClient 的逻辑也差不多,只是创建方式更加时髦了:

//创建 builder
HttpClient.Builder builder = HttpClient.newBuilder(); //链式调用
HttpClient client = builder //http 协议版本 1.1 或者 2
.version(HttpClient.Version.HTTP_2) //.version(HttpClient.Version.HTTP_1_1) //连接超时时间,单位为毫秒
.connectTimeout(Duration.ofMillis(5000)) //.connectTimeout(Duration.ofMinutes(1)) //连接完成之后的转发策略
.followRedirects(HttpClient.Redirect.NEVER) //.followRedirects(HttpClient.Redirect.ALWAYS) //指定线程池
.executor(Executors.newFixedThreadPool(5)) //认证,默认情况下 Authenticator.getDefault() 是 null 值,会报错
//.authenticator(Authenticator.getDefault()) //代理地址
//.proxy(ProxySelector.of(new InetSocketAddress("http://www.baidu.com", 8080))) //缓存,默认情况下 CookieHandler.getDefault() 是 null 值,会报错
//.cookieHandler(CookieHandler.getDefault()) //创建完成
.build();

在 builder() 方法中,最终会调用到 HttpClientImpl 的构造器,完成 HttpClient 的创建工作:

    //HttpClientImpl.class
private HttpClientImpl(HttpClientBuilderImpl builder,
SingleFacadeFactory facadeFactory) {
//CLIENT_IDS 是 AtomicLong 类型的变量,使用 incrementAndGet() 方法实现自增长的 id
id = CLIENT_IDS.incrementAndGet();
//记录下存有 id 的字符串
dbgTag = "HttpClientImpl(" + id + ")"; //ssl 认证
if (builder.sslContext == null) {
try {
sslContext = SSLContext.getDefault();
} catch (NoSuchAlgorithmException ex) {
throw new InternalError(ex);
}
} else {
sslContext = builder.sslContext;
} //线程池,没有的话就默认创建一个
Executor ex = builder.executor;
if (ex == null) {
ex = Executors.newCachedThreadPool(new DefaultThreadFactory(id));
isDefaultExecutor = true;
} else {
isDefaultExecutor = false;
}
delegatingExecutor = new DelegatingExecutor(this::isSelectorThread, ex);
facadeRef = new WeakReference<>(facadeFactory.createFacade(this)); //处理 http 2 的 client 类
client2 = new Http2ClientImpl(this);‘
//缓存操作
cookieHandler = builder.cookieHandler;
//超时时间
connectTimeout = builder.connectTimeout;
//转发策略,默认为 NEVER
followRedirects = builder.followRedirects == null ?
Redirect.NEVER : builder.followRedirects;
//代理设置
this.userProxySelector = Optional.ofNullable(builder.proxy);
this.proxySelector = userProxySelector
.orElseGet(HttpClientImpl::getDefaultProxySelector);
if (debug.on())
debug.log("proxySelector is %s (user-supplied=%s)",
this.proxySelector, userProxySelector.isPresent());
//认证设置
authenticator = builder.authenticator;
//设置 http 协议版本
if (builder.version == null) {
version = HttpClient.Version.HTTP_2;
} else {
version = builder.version;
}
if (builder.sslParams == null) {
sslParams = getDefaultParams(sslContext);
} else {
sslParams = builder.sslParams;
}
//连接线程池
connections = new ConnectionPool(id);
connections.start();
timeouts = new TreeSet<>(); //SelectorManager 本质上是 Thread 类的封装
//selmgr 会开启一条线程,HttpClient 的主要逻辑运行在此线程中
//所以说 HttpClient 是非阻塞的,因为并不跑在主线程中
try {
selmgr = new SelectorManager(this);
} catch (IOException e) {
throw new InternalError(e);
}
//设置为守护线程
selmgr.setDaemon(true);
filters = new FilterFactory();
initFilters();
assert facadeRef.get() != null;
}

主要是一些储存操作,大致理解即可,不细究。

二、HttpRequest

HttpRequest 是发起请求的主体配置:

//创建 builder
HttpRequest.Builder reBuilder = HttpRequest.newBuilder(); //链式调用
HttpRequest request = reBuilder //存入消息头
//消息头是保存在一张 TreeMap 里的
.header("Content-Type", "application/json") //http 协议版本
.version(HttpClient.Version.HTTP_2) //url 地址
.uri(URI.create("http://openjdk.java.net/")) //超时时间
.timeout(Duration.ofMillis(5009)) //发起一个 post 消息,需要存入一个消息体
.POST(HttpRequest.BodyPublishers.ofString("hello")) //发起一个 get 消息,get 不需要消息体
//.GET() //method(...) 方法是 POST(...) 和 GET(...) 方法的底层,效果一样
//.method("POST",HttpRequest.BodyPublishers.ofString("hello")) //创建完成
.build();

三、发送

发起请求:

    HttpResponse<String> response =
client.send(request, HttpResponse.BodyHandlers.ofString());
这是同步式的发起请求方式,先来看一下它的实现:
   public <T> HttpResponse<T> send(HttpRequest req, BodyHandler<T> responseHandler)
throws IOException, InterruptedException{
CompletableFuture<HttpResponse<T>> cf = null;
try {
//调用 sendAsync(...) 方法异步地完成主逻辑,并获取 Future
cf = sendAsync(req, responseHandler, null, null);
return cf.get();       //这之后的所有代码都是在进行异常捕捉,所以可以忽略
} catch (InterruptedException ie) {
if (cf != null )
cf.cancel(true);
throw ie;
} catch (ExecutionException e) {
final Throwable throwable = e.getCause();
final String msg = throwable.getMessage(); if (throwable instanceof IllegalArgumentException) {
throw new IllegalArgumentException(msg, throwable);
} else if (throwable instanceof SecurityException) {
throw new SecurityException(msg, throwable);
} else if (throwable instanceof HttpConnectTimeoutException) {
HttpConnectTimeoutException hcte = new HttpConnectTimeoutException(msg);
hcte.initCause(throwable);
throw hcte;
} else if (throwable instanceof HttpTimeoutException) {
throw new HttpTimeoutException(msg);
} else if (throwable instanceof ConnectException) {
ConnectException ce = new ConnectException(msg);
ce.initCause(throwable);
throw ce;
} else if (throwable instanceof IOException) {
throw new IOException(msg, throwable);
} else {
throw new IOException(msg, throwable);
}
}
}

本质上是使用了异步实现方法 sendAsync(…)。

在 Demo 中也可以直接使用:

    //返回的是 future,然后通过 future 来获取结果
CompletableFuture<String> future =
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body);
//阻塞线程,从 future 中获取结果
String body = future.get();

  

JDK 之 HttpClient(jdk11)的更多相关文章

  1. 工具篇:apache-httpClient 和 jdk11-HttpClient的使用

    关注公众号,一起交流,微信搜一搜: 潜行前行 HttpClient (apache) apache HttpClient 是 java项目里 较为常用的组件之一:对接外部服务时,各个商家提供的接口是各 ...

  2. JDK10、JDK11、JDK12新特性

    JDK10新特性 1.var声明变量 很多人抱怨Java是一种强类型,需要引入大量的样板代码.甚至在这些情况下,给定好变量名,通常很清楚发生了什么,明显类型声明往往被认为是不必要的.许多流行的编程语言 ...

  3. linux18.04下安装的jdk11.0.2

    1.百度搜索jdk,选择jdk11.0.2,操作如下图: 2.下载完成,ctrl+alt+t打开终端并在/usr/local创建java文件夹 cd /usr/local sudo mkdir /us ...

  4. [Jenkins]JDK版本过高导致的java.io.IOException: Remote call on xxxx failed

    ------------------------------------------------------ 如需转载,请注明出处. 文章链接:https://www.cnblogs.com/dzbl ...

  5. 新手上路之JDK11的下载、安装与PATH环境变量的配置

    目录 JDK11的下载 找到目标JDK JDK的下载 JDK11的安装 PATH环境变量的配置 为什么要配置环境变量? 配置前再检查一遍 配置变量 检查环境变量配置成功与否 细究起来,JDK11与JD ...

  6. Java5~11新特性

    Java5~11版本新特性 Java5 Java6 Java7 Java8 Java9 Java10 Java11 Java5 Java5开发代号为Tiger(老虎),于2004-09-30发行 特性 ...

  7. java5-11各个版本新特性

    转载:https://blog.csdn.net/zl1zl2zl3/article/details/85055948 Java 5 Java5开发代号为Tiger(老虎),于2004-09-30发行 ...

  8. Java SE 9 新增特性

    Java SE 9 新增特性 作者:Grey 原文地址: Java SE 9 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new_ ...

  9. Java SE 11 新增特性

    Java SE 11 新增特性 作者:Grey 原文地址:Java SE 11 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

随机推荐

  1. P3293-[SCOI2016]美味【主席树】

    正题 题目链接:https://www.luogu.com.cn/problem/P3293 题目大意 给出一个长度为\(n\)的序列,\(m\)次询问给出\(b,x,l,r\)表示询问在\([l,r ...

  2. 这是我见过最简单的博客文只有一张图,Python基础10分钟学完

  3. 02-token

    随着互联网技术的发展,cookie+session形式的用户认真逐渐不适应需求的扩展.在当前分布式微服务广泛流行的场景下,显然这种cookie+session无法满足,因为各个服务之间无法相互获取se ...

  4. Anaconda和canda简介及区别

    Anaconda简介: 1.是一个开源的Python发行版本,其包含了conda.Python等软件包,numpy,pandas(数据分析),scipy等科学计算包,而无需再单独下载配置. 可以在同一 ...

  5. C#实例:datagridview单元格合并

    这是替C#微信交流群群友做的一个小实例,目的就是在datagridview选择对应行以后,点击button后获取对应行的ip,并执行相应的操作,其实我觉得这样的话button没必要非放置到datagr ...

  6. sqlserver 2000 insert注入的问题

    一个sql server 2000的注入点猜测语句如下:insert into t1(col1, col2, col3) values('注入点1','数据点2','xxx');注入点1的值可以通过o ...

  7. 三种方法求解最大子区间和:DP、前缀和、分治

    题目 洛谷:P1115 最大子段和 LeetCode:最大子序和 给出一个长度为 \(n\) 的序列 \(a\),选出其中连续且非空的一段使得这段和最大. 挺经典的一道题目,下面分别介绍 \(O(n) ...

  8. caffe运行错误 target_blobs.blobs_size()与 source_layer.blobs_size() 不一致

    解决方法参考:http://blog.csdn.net/zhangla1220/article/details/50697352 感谢博主!!! 最新下载的caffe代码,运行mnist,训练时可以正 ...

  9. 题解 SP6779 【GSS7 - Can you answer these queries VII】

    题目传送门 题目大意 给出一个\(n\)个点的树,每个点有权值.有\(m\)次操作,每次要么查询一条链上的最大子段和,要么把一条链的权值都修改为一个常数. \(n,m\le 10^5\) 思路 如果是 ...

  10. EPUB文件格式简单解析

    最近热衷于看轻小说,奈何某些网站样式排版属实糟糕,移动端体验极度不友好,实在无法忍受,于是希望能将网站内容爬取下来制作成EPUB格式的电子书. 抛开爬取网站内容不谈,通过解析EPUB文件后,大致掌握了 ...