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.classprivate HttpClientImpl(HttpClientBuilderImpl builder,SingleFacadeFactory facadeFactory) {//CLIENT_IDS 是 AtomicLong 类型的变量,使用 incrementAndGet() 方法实现自增长的 idid = 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;//转发策略,默认为 NEVERfollowRedirects = 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(...) 方法异步地完成主逻辑,并获取 Futurecf = 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();

  

转载于:https://www.cnblogs.com/JiangWJ/p/10823112.html

JDK 之 HttpClient(jdk11)相关推荐

  1. 对于局部变量_2020年对于JDK ,大家觉得哪个版本好用?

    自95年以后,IT世界红红红火火,恍恍惚惚的,很多人都在议论纷繁,或许早在95年之前,就有大家小家一起拼个你死我不活的境界. 那么问题来咯,2020年的程序员们,讨论一下对于JDK,大家觉得什么版本好 ...

  2. JDK10、JDK11、JDK12新特性

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

  3. 新版本jdk(9、11、12、13、14)特性

    目录 背景 jdk9新特性 目录结构的改变 模块化系统 要解决的问题 概念 实现目标 示例 jShell命令 多版本兼容jar包 接口中的私有方法 钻石操作符(泛型)的升级 try语句的升级 下划线命 ...

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

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

  5. 2021-07-06-Intellij IDEA新建项目时JDK以及模块语言等级(language level)默认为1.8或1.5,每次创建新项目都需要重新更改

    问题详细描述:本人装了两个版本的JDK(JDK1.8 也叫JDK 8和JDK11)以前IDEA使用的都是JDK1.8,有时偶尔用11来看看新特性.今天想将IDEA的默认JDK换成11(language ...

  6. JDK 9 中有哪些 jmod 文件?

    JDK 9 jmods 目录中有97个jmod文件,这些文件都是干嘛的呢?我们在写代码的时候,都应该怎么用呢? /Library/Java/JavaVirtualMachines/jdk-9.jdk/ ...

  7. mac安装java开发环境-包含JDK、Maven、Svn、Idea

    由于业务发展需要,换了一台mac pro,发现安装本地开发环境步骤比较多,问题较多,再此将本次安装遇到的问题记录下来,以便后续观看 下载与安装JDK 下载JDK JDK8.JDK11可点击获取,也可以 ...

  8. jdk版本升级、技术选型

    目录 项目jdk版本升级 技术选型要考虑的因素 使用第三方框架遇到问题的解决途径 项目jdk版本升级 OracleJDK.OpenJDK的区别:OracleJDK是商业版本,收费:OpenJDK是开源 ...

  9. ubuntu16 安装 jdk11

    前言: 由于很多开发环境需要用到java的支持,我为了方便自己的工作,还是写下该文章为大家提供学习,有需要的可以按照操作(最好测试环境测试安装!!!),我不希望任何人直接应用到实际环境,因为ubunt ...

最新文章

  1. SpringBoot conditional注解和自定义conditional注解使用
  2. 查询name和age当name相同时选择age最大的
  3. AI 开发指南:机器学习产品是什么?
  4. C基础(31——35)
  5. exchange 2010 中OAB 排错一例
  6. python内置数据结构_Python基础知识2-内置数据结构(下)
  7. Atomic Integer 原理分析-getAndIncrement
  8. 电脑编程教学_2020太原数控车床电脑编程一对一实操教学不限学时
  9. xpath helper小工具的安装
  10. 7-1 两个有序链表序列的合并 (15 分)
  11. 已经到了退休年龄的城乡居民,可以一次性补交十五年的养老金吗?
  12. Spring中都用到了哪些设计模式
  13. htc328d屏幕排线怎么换_HTC T328D解锁详细图文教程
  14. 新华三培训2---HSRP/VRRP/GLBP
  15. JsessionId简介与过滤
  16. 信号与系统 徐亚宁 matlab程序,信号与系统分析 [徐亚宁,李和主编] 2010年版
  17. spring boot + websocket 简单实现斗鱼弹幕功能
  18. 国内使用cousera
  19. 关于n维和n-1维欧式空间的理解(转)
  20. 动态表情与超链接制作

热门文章

  1. linqto 多个关键字模糊查询_查询函数Choose、Lookup、Hlookup、Vlookup应用技巧解读
  2. android textview 动态高度自适应,TextView自适应高度(解决_UITextContainerView布局问题)...
  3. 电子计算机厂 四月份生产计,一题多解 分数和百分数应用题(1)
  4. 数据结构:列表(双向链表)的了解与示例
  5. java arraylist length,在Java中调整ArrayList的大小时,无法理解溢出的可能性
  6. 使用Electron将Web项目打包成windows桌面应用
  7. Python爬虫之Cookie和Session(转载)
  8. 进入Docker容器的4种方式
  9. hibernate和struts实现分页
  10. SGU 210 Acdream 1227 Beloved Sons KM