那个执事,争先:我如何于 2015 年在 Java Web 项目中推动 HTTP/2

  2015 年 5 月,HTTP/2 发布。
  
  2015 年第 3 季度,我所在企业的一个战略级客户(而且是第二大客户)说,他们需要在当年年底之前支持 HTTP/2(原因忘了,且与本文无关,从略)。
  
  而在当时,Tomcat、Jetty、Undertow 等都还不支持 HTTP/2,Nginx 虽然已开始紧锣密鼓的添加对 HTTP/2 的支持,但等别人总不是个办法。依我对 Java 世界干什么都慢三拍的了解,一旦别人进度稍慢或者出现了隐蔽的坑,还是要自己来搞。更重要的原因是,我们需要更简单的部署方式,需要更好地应对弱网环境,作为一个中型企业,还需要形成现代的、可通用的、自主可控的技术积累。
  
  求人不如求己,自己搞吧。
  
  劝君免谈 Java EE
  
  既然是搞 Java Web,那么 Servlet 总是被人们提起,作为 Java EE 中存在感最高的标准,它被众多 Servlet 容器所支持,在世界各地的机房闪闪发光。
  
  而自从接触 Java 的第一天,我就在想,Servlet,乃至更大范围的 Java EE, 在这个年头到底还有什么用?
  
  很多朋友可能知道,Java EE 是若干个标准的总称,包括而不限于:Servlet、JSP、EJB、JTA、JPA、JSF、JMS(完整列出来有好几十个)。随着服务化、多语言开发、前后端分离的兴起,Java EE 在技术比较新的公司(尤其是那几个知名的互联网公司)迅速被边缘化,其中的 Servlet 的重要性也日趋减小。要知道,标准的意义在于协作,但谁又会没事换容器玩?前后端、服务之间的调用一般通过 REST 或 RPC,前者与是否采用 Servlet 毫无关系,后者更没有 Servlet 什么事。
  
  我大胆地下判断:是时候抛弃 Java EE 了。
  
  事实上,后序几年的技术发展也印证了我的判断。
  
  Java EE 被 Oracle 抛弃而独立发展,标志着不接地气的 Java EE 全面败给了 Spring 开源栈。
  
  Spring Boot 内置容器方式使得 Java Web 程序在外部看来是 HTTP Server 而非 Servlet,如此一来,Servlet 容器的部分就可以被取代,例如,Spring 5 提供的 WebFlux 底层就可以在 netty 而非 Servlet 之上构建。
  
  语言无关的基础设施的涌现,使得 Java EE 的用处越来越少。
  
  越来越多的优秀 Java 工程师不再知道 Java EE 是什么。
  
  当然,这些都是后话。当时我要做的,就是赶快把一个被定名为 Fxxxx 的框架搞出来,无论是否用 Servlet。
  
  网络库上的抉择
  
  我当时所任职的那家企业,有着深厚的桌面软件背景和服务器软件背景,内部有大量 C/C++ 基础设施,其中就包括高性能的 TCP、UDP 网络库。它分别在 Windows、macOS、Linux 下,封装了性能最好的网络模型 I/O 完成端口、kqueue、epoll,在多个重要产品中稳定运行。
  
  我对这些设施当然是信任的,唯一要考虑的问题是,如果用 Java 来包装它们,不可避免要用到大量的 JNI,这样一来,维护成本大大增加,构建、调试都比较困难。而当时 netty 也很成熟了,它也封装了各个平台上的高性能网络模型。尽管 netty 内部也有 JNI,但它久经考验且外部感知不到,也节省了把 C++ 库包装为 Java 库的时间(这挺费事的,由于 C++ 多范式且特性丰富,两门语言不大容易优美地对话,另外,那些 C++ 代码时间太久了,有些地方也腐化了)。
  
  netty 尽管也有一些坑,例如,服务端意外退出,ByteBuf 奇怪错误,连接池资源泄露,等等。不过,同事们当中有经验丰富的,基本上坑都踩过,所以问题不大。
  
  最终的选择是 netty。同事和业界高手,我同样报以信任。
  
  主要 API
  
  HTTP 服务器 API 大概这个样子:
  
  Server.createDefault()
  
  .route("GET", ((resp, req) www.ysyl157.com-> {
  
  //
  
  }))
  
  .andRoute("POST", ((resp, req) -> {
  
  //
  
  }))
  
  .andRoute("PUT", ((resp, req) -> {
  
  //
  
  }))
  
  .StartTLS(cert, key, 443);
  
  或者这个样子:
  
  @Namespace(prefix = "/model")
  
  public class ModelNamespace {
  
  @Router(pattern = "/{id}/predict", method = "POST")
  
  public void predict(Context ctx, String id) {
  
  //
  
  }
  
  @Router(pattern = "/{id}/info"www.dasheng178.com,www.tiaotiaoylzc.com/ method = "GET")
  
  public void info(Response resp, Request req, String id) {
  
  //
  
  }
  
  }
  
  HTTP 客户端大概这个样子:
  
  // 省略了错误处理
  
  Client client = new Client();
  
  Response resp = client.doSync(req); // 同步地
  
  CompletableFuture<Response> respOther www.hengda157.com= client.doAsync(req); // 异步地
  
  客户端方面,如果对方的服务器支持 HTTP/2,则运用多路复用,否则,会维护一个连接池。
  
  翔一样的 java.net.HttpURLConnection 实在不想再用了。
  
  实现 HTTP/2
  
  实现 HTTP/2 协议解析,把握核心概念是关键:
  
  数据流(stream)
  
  消息(message)
  
  帧(frame)
  
  由于之前对 SPDY(HTTP/2 的前身)不熟,所以理解这些概念还是费了一些力气的,不过好在最后也弄清楚了。数据流的优先级,处理依赖和权重,帧的分割和组装,HPACK 中的霍夫曼树编码(好像又回到了学生时代),服务端推送……不知经过了多少次调试、检查、修改,最后在 Chrome 和 Firefox 上测试成功了。当然,最重要的是客户满意了,这个项目也作为我们的技术积累。
  
  DAO 模块 & Spring 整合模块
  
  这两个地方没什么可说的,把 Hibernate 和 MyBatis 浅浅包装了一下,再加上连接池。连接池这块,我抽象出了“策略”接口,这样,使用者如果对内置的连接池(c3p0 等)不满意,则可通过实现策略的方式自己来搞。
  
  而整合 Spring 是为了要它的依赖注入、切面织入、事务管理等功能。
  
  进化为 Spring Boot Starter
  
  再后来,随着 Spring Boot 的日渐成熟完善,我们将其引入了生产环境。同时,将 Fxxxx 去掉 DAO 模块和 Spring 整合模块,专注 Web 层,改为了 Spring Boot Starter。如此一来,Fxxxx 和 Spring 全家桶整合到一起,用起来更加舒畅。
  
  继往开来
  
  后来,我离开了这个团队。
  
  技术的发展却一直没有停下脚步,几乎所有的基础实施都开始支持 HTTP/2 了,如 Nginx 1.10,Tomcat 9,新版本的 Undertow。OkHttp 则提供了精美的支持 HTTP/1.1 和 HTTP/2 的客户端,而后 Java 9 也做到了这一点。
  
  随着行业技术进步,这个项目的存在意义越来越小了。但它包含了我们技术人不畏艰难,别人没有就自己干的精神,激励着我前行。

原文地址:https://www.cnblogs.com/qwangxiao/p/10325259.html

时间: 2024-11-08 09:53:27

那个执事,争先:我如何于 2015 年在 Java Web 项目中推动 HTTP/2的相关文章

java web开发中的奇葩事web.xml中context-param中的注释

同事提交了代码.结果除同事之外,其他人全部编译报错.报错说web.xml中配置的一个bean 没有定义.按照报错提示,各种找,无果. 由于代码全部都是提交到svn主干,之前也没有做过备份,只能一步一步删除同事提交的代码,进行还原. 奇葩事情出现了! <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:/context_entry.xml

关于java项目与web项目中lib包的那点事

一.在java项目中如何引入外部jar包:1.在我们的java项目下新建一个lib文件夹:2.将我们需要引入的jat包复制到lib文件夹下:3.选中我们lib包下的jar,右键选择Build Path --Add to Build Path: 4.jar成功的添加到Referenced Libraries中. 这样做的目的主要是为了防止绝对路径的引用导致我们的工程依赖本工程目录下的jar包文件. 二.web项目,新建之时会默认出现lib包,只要把相关jar包复制到lib文件下,理论上会自动加载到

Visual Studio 2015下编译zmq项目下其他项目踩进的项目引用坑

PS.在之前的一篇文章中介绍了如何用Visual Studio 2015编译zmq,在编译同解决方案中除了libzmq之外的项目例如inproc_thr时会报错误,具如下: Severity Code Description Project File Line Suppression State Error LNK1181 cannot open input file 'libzmq.lib' inproc_thr E:\zeromq4-1-master\zeromq4-1-master\bui

(图文)在MyEclipse(2015)中上传项目到github的步骤(很详细)

MyEclipse 2015 默认已经安装了git插件,在MyEclipse中上传项目到github的步骤如下: (原创文章,转载请注明转自Clement-Xu的博客:http://blog.csdn.net/clementad/article/details/46954587) 1.github官网(https://github.com)申请开通账号(略) 1.1.然后,在github网站登录后创建一个仓库(也就是项目)(假设仓库/项目名字为:HttpApp): 1.2.创建成功后,就自动跳转

工作那些事(二十七)项目经理在项目中是什么角色?

项目经理在项目中是什么角色? 有人说,项目经理就是一个求人的差事,你是在求人帮你做事.这样的说法在中国特色下,有一定道理.可是,我不全然认同.我认为项目经理室一个为项目组人员服务的角色.更像是后勤保障部长的角色. 有人说.项目经理就是一个与人扯皮的差事,你要不断的与开发.产品.測试等之间沟通.协调. 有人说,有人的地方,就有江湖,有江湖的地方,就有规矩.确实,在做项目的时候,有的人是为了完毕功能,有的人是为了学到东西,有的人是为了混日子. 哪种人最适合你的项目?你的项目.有没有被所谓的专家坑过?

使用Team Explorer Everywhere (TEE) 2015 SDK获取团队项目的签入策略

TFS的代码签入策略与IDE工具紧密相关,例如Visual Studio中设置的签入策略,只会影响Visual Studio的团队资源管理器:如果需要在Eclipse的TEE中启用签入策略,你还需要在TEE中单独设置.(不仅如此,在数据存储上,二者也不一样,通过查询数控,我们发现TEE的签入策略存储在Collection数据库的表tbl_PropertyValue中,VS则不是). 如果需要统计或查询哪些团队项目启用了什么签入策略,我们可以通过报表或者API的方式编写脚本输出TFS的签入策略设置

工作那些事(二十八)项目管理模式:项目型、职能型、矩阵型

在一个项目中,项目经理有多大权利,可以动用哪些资源,取决于项目管理模式,项目管理模式由公司的CTO来决定.简而言之,项目管理有三种模式:项目型.职能型.矩阵型. 下面先看看这三种模式,对项目经理来说都是什么作用. 1项目型 将所有的能兵强将集结在一起,财务部.业务部.IT管理部等的精英们脱离原有的岗位.形成一个正式的部门,并由项目经理领导.这样的优势是项目经理的权利很强.资源充足,所有的项目经理都希望有这样的团队.但是就公司而言,单独团队对公司整体资源的浪费,是显而易见的:对被抽调的个人而言,脱

vue项目中遇到的那些事。

前言 有好几天没更新文章了.这段实际忙着做了一个vue的项目,从 19 天前开始,到今天刚好 20 天,独立完成. 做vue项目做这个项目一方面能为工作做一些准备,一方面也精进一下技术. 技术栈:vue2 + vuex + vue-router + webpack + ES6/7 + element-ui + vue-baidu-map + i18n + vue-awesome-swiper 做项目时总是有一些思考和踩过的坑,对以后有一定的帮助,今天就来写写做vue项目遇到的那些事. 假如你正准

在Visual Studio 2015的Cordova项目中使用Gulp

之前一直是在vs 2013中使用Cordova来开发移动app(目前有iPad版/iPhone版/安卓版),准备到下一个milestone的时候升级到2015,这两天在尝试各种东西. 2015中的cordova项目和2013结构变化很大,所以需要一个手动迁移过程,这个过程之前已经有同事尝试过了,包括很多插件可能都要重新安装,不同插件的使用可能还有些不太一样. 这两天在研究如何在项目里使用gulp这个前端集成工具,vs 2015支持这个东西是一个非常大的利好,之前很多事情现在都可以自动来做了. g