JDK 之 HttpClient(jdk11)
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)的更多相关文章
- 工具篇:apache-httpClient 和 jdk11-HttpClient的使用
关注公众号,一起交流,微信搜一搜: 潜行前行 HttpClient (apache) apache HttpClient 是 java项目里 较为常用的组件之一:对接外部服务时,各个商家提供的接口是各 ...
- JDK10、JDK11、JDK12新特性
JDK10新特性 1.var声明变量 很多人抱怨Java是一种强类型,需要引入大量的样板代码.甚至在这些情况下,给定好变量名,通常很清楚发生了什么,明显类型声明往往被认为是不必要的.许多流行的编程语言 ...
- linux18.04下安装的jdk11.0.2
1.百度搜索jdk,选择jdk11.0.2,操作如下图: 2.下载完成,ctrl+alt+t打开终端并在/usr/local创建java文件夹 cd /usr/local sudo mkdir /us ...
- [Jenkins]JDK版本过高导致的java.io.IOException: Remote call on xxxx failed
------------------------------------------------------ 如需转载,请注明出处. 文章链接:https://www.cnblogs.com/dzbl ...
- 新手上路之JDK11的下载、安装与PATH环境变量的配置
目录 JDK11的下载 找到目标JDK JDK的下载 JDK11的安装 PATH环境变量的配置 为什么要配置环境变量? 配置前再检查一遍 配置变量 检查环境变量配置成功与否 细究起来,JDK11与JD ...
- Java5~11新特性
Java5~11版本新特性 Java5 Java6 Java7 Java8 Java9 Java10 Java11 Java5 Java5开发代号为Tiger(老虎),于2004-09-30发行 特性 ...
- java5-11各个版本新特性
转载:https://blog.csdn.net/zl1zl2zl3/article/details/85055948 Java 5 Java5开发代号为Tiger(老虎),于2004-09-30发行 ...
- Java SE 9 新增特性
Java SE 9 新增特性 作者:Grey 原文地址: Java SE 9 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new_ ...
- Java SE 11 新增特性
Java SE 11 新增特性 作者:Grey 原文地址:Java SE 11 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
随机推荐
- 基于Processing图像序列处理保存导出的流程梳理
做一个基于processing的图像序列处理保存导出的流程梳理.本案例没有什么实质性的目的,仅为流程梳理做演示. 准备 把需要处理的影像渲染成序列图片,可以在PR中剪辑并导出PNG序列[格式倒是没什么 ...
- Vulnhub靶机渗透 -- DC6
信息收集 开启了22ssh和80http端口 ssh可以想到的是爆破,又或者是可以在靶机上找到相应的靶机用户信息进行登录,首先看一下网站信息 结果发现打开ip地址,却显示找不到此网站 但是可以发现地址 ...
- Spring MVC面试复习整理
Spring MVC Spring MVC 是Spring Framework 提供的 web 组件 它的实现基于 MVC 的设计模式:Model(模型层).View(视图层).Controller( ...
- 13万字详细分析JDK中Stream的实现原理
前提 Stream是JDK1.8中首次引入的,距今已经过去了接近8年时间(JDK1.8正式版是2013年底发布的).Stream的引入一方面极大地简化了某些开发场景,另一方面也可能降低了编码的可读性( ...
- CentOS7下Hadoop伪分布式环境搭建
CentOS7下Hadoop伪分布式环境搭建 前期准备 1.配置hostname(可选,了解) 在CentOS中,有三种定义的主机名:静态的(static),瞬态的(transient),和灵活的(p ...
- HC(Histogram-based Contrast) 基于直方图对比度的显著性
HC(Histogram-based Contrast) 基于直方图对比度的显著性 来源于: 2011, Global contrast based salient region detection, ...
- Mybatis、maven项目中整合log4j (17)
Mybatis.maven项目总整合log4j java 中Mybatis.maven项目总整合log4j 1.pom增加log4j包引用 2.添加 log4j.properties文件 # java ...
- 《看漫画学Pyhton》中计算水仙花数
利用while循环实现 i = 100 r = 0 s = 0 t = 0 while i < 1000: r = i // 100 s = (i - r * 100) // 10 t = i ...
- 【Python从入门到精通】(二)怎么运行Python呢?有哪些好的开发工具(PyCharm)
您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦. 这是Pyhon系列文章的第二篇,本文主要介绍如何运行Python程序以及安装PyCharm开发工具. 干货满满,建议收藏,需要用到时常看看. 小伙 ...
- BUAA软件工程个人项目作业
BUAA软件工程个人项目作业 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人项目作业 我在这个课程的目标是 学习软件开发的流程 这个作业在哪 ...