Java9 的 HTTP2 和 REPL 有哪些新功能?

对JAVA 9的炒作将不再局限于模块化(modularity),Java 9正在搜罗大量额外的功能模块,这些功能模块正作为Java增强提案(JEP)提交,并在OpenJDK (Java SE的参考实现项目)中实现 。
在这篇文章中,我们将重点关注一些或将在Java 9整个生命周期中,对开发者的工作生活影响最大的JEP,包括新的HTTP/2支持和JShell REPL(读取-求值-打印-循环),后者带来了基于shell的交互式Java开发环境和探索性开发API 。
HTTP/2HTTP/2标准是HTTP协议的最新版本 。当前版本HTTP/1.1始于1999年,存在着非常严重的问题,包括:
对头阻塞在HTTP/1.1中,响应接收的顺序和请求发送的顺序相同 。这意味着,例如,当查看一个包含许多小图像的大html页面时,图像资源将不得不在HTML页面资源之后排队,在浏览器完全加载完HTML页面之前,图像资源无法被发送 。这就是“对头阻塞”,会导致许多潜在的页面渲染问题 。
在HTTP/2中,响应数据可以按块(chunk)传输,甚至可以交叉传输,因此真正实现了请求和响应的多路复用 。
一个站点的连接数限制在HTTP/1.1标准中有这样的描述:“一个单用户的客户端不能与任何服务器保持2个以上的连接” 。这个限制和对头阻塞问题一起,严重限制了页面的性能 。
HTTP/2打破这种限制并认为连接是持久的,只有当用户跳转后或者发生技术性故障事件时,连接才会关闭 。对多路复用的使用将有助于降低页面性能瓶颈 。
HTTP控制头的开销当前的HTTP版本使用简单的、基于文本的HTTP头信息来控制通信 。这样做的优点是非常简单且易于理解,调试也很简单,只需通过连接指定端口并输入一些文本 。然而,使用基于文本的协议会让小的响应包不成比例地膨胀 。此外,大量的HTTP响应几乎没有或者根本没有有效负载(比如,HEAD请求只是要确定资源是否发生变化) 。为实际上只包含最后修改时间的响应,使用完全基于文本的头信息(大约有700个字节,在HTTP1.1中,它们不能被压缩,尽管很容易做到)是当前HTTP标准中,不可思议的浪费 。
另一个思路是对HTTP头信息使用二进制编码 。这种方式能够极大地提高较小请求的速度且占用的网络带宽非常小 。这正是HTTP/2已经选择的方法,虽然以协议精神制定标准应该选择基于文本的协议,但是二进制的效率有令人信服的理由,让我们这样做 。
HTTP/2带来的期望HTTP/2标准是由IETF HTTP工作组创建的,该组织由来自Mozilla、google、 Microsoft、Apple,以及其他公司的代表和工程师组成,由来自CDN领军公司Akamai的高级工程师Mark Nottingham任主席 。因此,HTTP/2是一个为优化大型、高流量的网站而生的版本,它在实现简单、易于调试的基础上,确保了性能和网络带宽消耗 。
该组织主席总结了一些HTTP/2的关键属性:

  • 相同的HTTP API
  • 成本更低的请求
  • 网络和服务器端友好
  • 缓存推送
  • 思维革命
  • 更多加密方式
带给Java的意义自从1.0版本开始,Java就支持HTTP,但是多数代码出自完全不同的时代 。例如,Java对HTTP的支持是围绕相对协议无关的框架(URL类)设计的,因此在网站成为主导地位的90年代,这种实现显得很不清晰 。
Java对HTTP的支持是基于当时最好的设计思想,但是时过境迁,最重要的是Java对HTTP原始的支持出来时,HTTPS还没有出现 。因此,Java的API将HTTPS作为一种移花接木,导致了不能简化的复杂性 。
在现代社会,HTTPS开始变得无所不在,让HTTP日渐成为落后的技术 。甚至,美国政府现在都通过了完全迁到HTTPS-only的计划 。
JDK内核对HTTP的支持已经无法跟上现实网络的发展步伐 。实际上,甚至JDK8也只不过是交付了一个支持HTTP/1.0的客户端,然而,大多数的开发者早已转而使用第三方客户端库了,比如Apache的HttpComponents 。
所有这一切意味着,对HTTP/2的支持将是Java未来十年的核心功能 。这也让我们重新审视我们的固有思维,重新写一套API并提供重新来过的机会 。HTTP/2将是未来数年内,每位开发者主要面对的API 。
新的API不再坚持协议中立性,使开发者可以完全抛弃过去的使用方式 。这套API只关注HTTP协议,但是要进一步理解的是HTTP/2并没有从根本上改变原有的语义 。因此,这套API是HTTP协议独立的,同时提供了对新协议中帧和连接处理的支持 。
在新的API中,一个简单的HTTP请求,可以这样创建和处理:
HttpResponse response = HttpRequest.create(new URI("http://www.infoq.com")).body(noBody()).GET().send();int responseCode = response.responseCode();String responseBody = response.body(asString());System.out.println(responseBody);


推荐阅读