Java9新功能之HTTP2和REPL

本文转自:云栖社区云java

  【摘要】对Java 9的炒做将再也不局限于模块化(modularity),Java 9正在搜罗大量额外的功能模块,这些功能模块正做为Java加强提案(JEP)提交,并在OpenJDK (Java SE的参考实现项目)中实现。 在这篇文章中,咱们将重点关注一些或将在Java 9整个生命周期中,对开发者的工做生...shell

  对Java 9的炒做将再也不局限于模块化(modularity),Java 9正在搜罗大量额外的功能模块,这些功能模块正做为Java加强提案(JEP)提交,并在OpenJDK (Java SE的参考实现项目)中实现。express

  在这篇文章中,咱们将重点关注一些或将在Java 9整个生命周期中,对开发者的工做生活影响最大的JEP,包括新的HTTP/2支持和JShell REPL(读取-求值-打印-循环),后者带来了基于shell的交互式Java开发环境和探索性开发API。数组

  HTTP/2浏览器

  HTTP/2标准是HTTP协议的最新版本。当前版本HTTP/1.1始于1999年,存在着很是严重的问题,包括:缓存

  对头阻塞服务器

  在HTTP/1.1中,响应接收的顺序和请求发送的顺序相同。这意味着,例如,当查看一个包含许多小图像的大HTML页面时,图像资源将不得不在HTML页面资源以后排队,在浏览器彻底加载完HTML页面以前,图像资源没法被发送。这就是“对头阻塞”,会致使许多潜在的页面渲染问题。网络

  在HTTP/2中,响应数据能够按块(chunk)传输,甚至能够交叉传输,所以真正实现了请求和响应的多路复用。app

  一个站点的链接数限制框架

  在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);

  这种符合流畅风格/建造者模式(fluent/builder)的API,与现存的遗留系统相比,对开发者来讲,更具现代感和温馨感。

  虽然当前的代码库只支持HTTP/1.1,可是已经包含了新的API。这使得在对HTTP/2支持完成对过程当中,开发者能够实验性地使用和验证新的API。

  相关代码已经进入OpenJDK沙箱仓库中,并很快登录JDK 9的主干。到那个时候,新的API将开始自动构建到Oracle的二进制beta版本中。如今,对HTTP/2的支持已经可用,并将在将来数月内最终完成。

  在此期间,你可使用Mercurial迁出源代码,并根据AdoptOpenJDK构建指导编译你迁出地代码,这样你就能够实验性地使用新的API了。

  第一批完成的功能之一是当前版本力不能及的异步API。这个功能让长期运行的请求,能够经过sendAsync()方法,切换到VM管理的后台线程中:

  HttpRequest req = HttpRequest .create(new URI("http://www.infoq.com")) .body(noBody()) .GET(); CompletableFuture<HttpResponse> aResp = req.sendAsync(); Thread.sleep(10); if (!aResp.isDone()) { aResp.cancel(true); System.out.println("Failed to reply quickly..."); return; } HttpResponse response = aResp.get();

  相比HTTP/1.1的实现,新的API带给开发者最多的是方便性,由于HTTP/1.1没有提供对已经发送到服务器端的请求的取消机制,而HTTP/2可让客户端向已经被服务器端处理的请求,发送取消命令。

  JShell

  不少语言都为探索性开发提供了交互式环境。在某些状况下(特别是Clojure和其余Lisp方言),交互式环境占据了开发者的大部分编码时间,甚至是所有。其余语言,好比Scala或者JRuby也普遍使用REPL。

  固然,此前Java曾经推出过Beanshell脚本语言,可是它没有实现彻底标准化,并且近年来,该项目已经处于不活跃状态。在Java 8(以及jjs REPL)中引入的Nashorn Java实现打开了更普遍地考虑REPL并将交互式开发成为可能的大门。

  一项努力将现代REPL引入Java 9的工做,以JEP 222做为开始,收录在OpenJDK的Kulla项目中。Kulla这个名字来自古巴比伦神话,是建造之神。该项目的主旨是提供最近距离的“完整Java”体验。该项目没有引入新的非Java语义,并禁用了Java语言中对交互式开发没有用处的语义(好比上层的访问控制修改或同步的语义)。

  与全部REPL同样,JShell提供了命令行,而不是相似IDE的体验。语句和表达式可以在执行状态上下文中,被当即求值,而不是非得打包到类中。方法也是自由浮动的,而没必要属于某个特定的类。相反,JShell使用代码片段“snippets”来提供上层执行环境。

  与HTTP/2 API类似,JShell已经在独立的项目开发,以避免在快速发展的时期影响主干构建的稳定性。JShell预计在2015年8月期间合并到主干。

  如今,开发者能够参考AdoptOpenJDK说明指导,从头构建Kulla(源代码能够从Mercurial地址得到)。

  对于一些上手实验,最简单的多是使用一个独立的试验jar。这些jar包是社区专为不想从头构建的开发者构建好的。

  这些试验jar包能够从AdoptOpenJDK CloudBees的CI构建实例中得到。

  要使用它们,你须要安装Java 9 beta版(或者OpenJDK 9的构建版本)。而后下载jar文件,重命名为kulla.jar,而后在命令行输入以下:

  $ java -jar kulla.jar | Welcome to JShell -- Version 0.610 | Type /help for help ->

  这是REPL的标准界面,和往常同样,命令是从单个字符开始并最终发出的。

  JShell有一个至关完整(但仍在发展)的帮助语法,能够经过以下命令轻松得到:

  -> /help Type a Java language expression, statement, or declaration. Or type one of the following commands: /l or /list [all] -- list the source you have typed /seteditor <executable> -- set the external editor command to use /e or /edit <name or id> -- edit a source entry referenced by name or id /d or /drop <name or id> -- delete a source entry referenced by name or id /s or /save [all|history] <file> -- save the source you have typed /o or /open <file> -- open a file as source input /v or /vars -- list the declared variables and their values /m or /methods -- list the declared methods and their signatures /c or /classes -- list the declared classes /x or /exit -- exit the REPL /r or /reset -- reset everything in the REPL /f or /feedback <level> -- feedback information: off, concise, normal, verbose, default, or ? /p or /prompt -- toggle display of a prompt /cp or /classpath <path> -- add a path to the classpath /h or /history -- history of what you have typed /setstart <file> -- read file and set as the new start-up definitions /savestart <file> -- save the default start-up definitions to the file /? or /help -- this help message /! -- re-run last snippet /<n> -- re-run n-th snippet /-<n> -- re-run n-th previous snippet Supported shortcuts include: -- show possible completions for the current text Shift- -- for current method or constructor invocation, show a synopsis of the method/constructor

  JShell支持TAB键自动补全, 所以咱们能够很容易找到println()或者其余咱们想使用的方法:

  -> System.out.print print( printf( println(

  传统的表达式求值也很容易,可是相比其余动态类型语言,Java的静态类型特征会更严格一点。JShell会自动建立临时变量来保存表达式的值,并确保它们保持在上下文域内供之后使用:

  -> 3 * (4 + 5) | Expression value is: 27 | assigned to temporary variable $1 of type int -> System.out.println($1); 27

  咱们还可使用/list命令,查看到目前为止输入的全部源代码:

  -> /list 9 : 3 * (4 + 5) 10 : System.out.println($1);

  使用/vars命令显示全部的变量(包括显式定义的和临时的),以及他们当前持有的值:

  -> String s = "Dydh da" | Added variable s of type String with initial value "Dydh da" -> /vars | int $1 = 27 | String s = "Dydh da"

  除了支持简单的代码行,REPL还容许很是简单地建立类和其它用户定义的类型。例如,能够用以下短短一行来建立类(请注意,开始和结束括号是必需的):

  -> class Pet {} | Added class Pet -> class Cat extends Pet {} | Added class Cat

  JShell代码很是简洁、自由浮动的性质意味着咱们能够很是简单地使用REPL来演示Java语言的功能。例如,让咱们来看看著名的类型问题,即Java数组的协变问题:

  -> Pet[] pets = new Pet[1] | Added variable pets of type Pet[] with initial value [LPet;@2be94b0f -> Cat[] cats = new Cat[1] | Added variable cats of type Cat[] with initial value [LCat;@3ac42916 -> pets = cats | Variable pets has been assigned the value [LCat;@3ac42916 -> pets[0] = new Pet() | java.lang.ArrayStoreException thrown: REPL.$REPL13$Pet | at (#20:1)

  这样的功能使JShell成为一种伟大的教学或研究工具,并且最接近Scala REPL的体验。使用/classpath切换,能够加载额外的jar包,从而能够在REPL直接使用互动式探索性API。

  参与

  主要的IDE已开始提供支持JDK 9早期版本的构建——包括Netbeans和Eclipse Mars。[urlhttps://www.jetbrains.com/idea/download/?spm=5176.blog26632.yqblogcon1.14.tXFWPP=""]IntelliJ 14.1[/url]据称支持JDK9,但目前还不清楚对新的模块化JDK扩展的支持力度。

  到目前为止,这些IDE还不支持HTTP/2和JShell,由于这些功能尚未登录OpenJDK的主干,可是开发者应该很指望它们可以早日出如今标准的JDK beta版本中,而且有IDE插件能够紧随其后。这些API仍在开发中,项目的领导者正在积极寻求最终用户的使用和参与。

  The JDK 9 Outreach programme is also underway to encourage developers to test their code and applications on JDK 9 before it arrives. HTTP/2 & JShell aren't the only new features being worked on - other new JDK 9 functionality under development as JEPs includes

  JDK 9的宣传计划也正在鼓励开发者测试他们的代码并在JDK 9上运行应用程序。正在开发的新功能不止包括HTTP/2和JShell—— 其余做为JEP,JDK 9正在开发的新功能还包括:

  102 Process API的更新(Process API Updates)165 编译器控制(Compiler Control)227 Unicode 7.0245 验证虚拟机代码行标记参数(Validate JVM Command-Line Flag Arguments)248: G1做为默认的垃圾回收器(Make G1 the Default Garbage Collector)TLS的一系列更新(TLS Updates) (JEP 219, 244, 249)

  目前正在审议(以及考虑应该放在哪一个Java版本)的全部JEP的完整列表能够在这里找到。

相关文章
相关标签/搜索