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 也做到了这一点。
  
  随着行业技术进步,这个项目的存在意义越来越小了。但它包含了我们技术人不畏艰难,别人没有就自己干的精神,激励着我前行。

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

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

    同事提交了代码.结果除同事之外,其他人全部编译报错.报错说web.xml中配置的一个bean 没有定义.按照报错提示,各种找,无果. 由于代码全部都是提交到svn主干,之前也没有做过备份,只能一步一步 ...

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

    一.在java项目中如何引入外部jar包:1.在我们的java项目下新建一个lib文件夹:2.将我们需要引入的jat包复制到lib文件夹下:3.选中我们lib包下的jar,右键选择Build Path ...

  3. jdbc “贾琏欲执事”

    “贾琏欲执事” 1.加载驱动2.获取连接3.SQL语句4.执行SQL5.释放资源 示例: public void test_insert() { String driver="oracle. ...

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

    PS.在之前的一篇文章中介绍了如何用Visual Studio 2015编译zmq,在编译同解决方案中除了libzmq之外的项目例如inproc_thr时会报错误,具如下: Severity Code ...

  5. Visual Studio 2015 与GitLab 团队项目与管理【2】

    前一篇介绍了Git服务器的搭建,我采用的是CentOS7-64位系统,git版本管理使用的是GitLab,创建管理员密码后进入页面. 创建Users,需要记住Username和邮箱,初始密码可以由管理 ...

  6. vue项目中遇到的那些事。

    前言 有好几天没更新文章了.这段实际忙着做了一个vue的项目,从 19 天前开始,到今天刚好 20 天,独立完成. 做vue项目做这个项目一方面能为工作做一些准备,一方面也精进一下技术. 技术栈:vu ...

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

    (图文)在MyEclipse(2015)中上传项目到github的步骤(很详细) git|smartGit使用详解 SmartGit使用教程

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

    TFS的代码签入策略与IDE工具紧密相关,例如Visual Studio中设置的签入策略,只会影响Visual Studio的团队资源管理器:如果需要在Eclipse的TEE中启用签入策略,你还需要在 ...

  9. python爬虫之爬取糗事百科并将爬取内容保存至Excel中

    本篇博文为使用python爬虫爬取糗事百科content并将爬取内容存入excel中保存·. 实验环境:Windows10   代码编辑工具:pycharm 使用selenium(自动化测试工具)+p ...

随机推荐

  1. centos7 python2.7.5 升级python3.6.4

    (转)Linux Centos7 升级python2至python3 - 依然范儿特西的文章 - 知乎 https://zhuanlan.zhihu.com/p/33660059 1 查看python ...

  2. json_encode替代函数

    <?php   function jsonEncode($var) {     if (function_exists('json_encode')) {         return json ...

  3. python终端计算器,还有没其他方法?

    import sysdef lt(a, b, c ): if b == "+": return int(a)+int(c) elif b == "-": ret ...

  4. Oracle同义词和序列

    同义词:是表.索引.视图的模式对象的一个别名,通过模式对象创建同意词,可以隐藏对象的实际名称和 所有者信息,为对象提供一定的安全性,开发应用程序时:应该尽量避免直接使用表,视图 或其他对象,改用对象的 ...

  5. 用Tensorflow完成简单的线性回归模型

    思路:在数据上选择一条直线y=Wx+b,在这条直线上附件随机生成一些数据点如下图,让TensorFlow建立回归模型,去学习什么样的W和b能更好去拟合这些数据点. 1)随机生成1000个数据点,围绕在 ...

  6. Jenkins之Sonar 代码检查

    一.简介 SonarQube 是一个用于代码质量管理的开放平台.通过插件机制,Sonar 可以集成不同的测试工具,代码分析工具,以及持续集成工具.与持续集成工具(例如 Hudson/Jenkins 等 ...

  7. [T-ARA][Lovey-Dovey]

    歌词来源:http://music.163.com/#/song?id=22704426 作曲 : 新沙洞老虎/崔圭成 [作曲 : 新沙洞老虎/崔圭成] [作曲 : 新沙洞老虎/崔圭成] 作词 : 新 ...

  8. 实现属于自己的TensorFlow(二) - 梯度计算与反向传播

    前言 上一篇中介绍了计算图以及前向传播的实现,本文中将主要介绍对于模型优化非常重要的反向传播算法以及反向传播算法中梯度计算的实现.因为在计算梯度的时候需要涉及到矩阵梯度的计算,本文针对几种常用操作的梯 ...

  9. 关于0x80000000为什么等于-2147483648和负数在内存上储存的问题

    转载自大佬的博客https://blog.csdn.net/youyou362/article/details/72667951/ 1·先说明负数怎么储存 (1)十进制负数是以其补码储存在内存上. 验 ...

  10. 20172329 2018-2019《Java软件结构与数据结构》第一周学习总结

    2018-2019-20172329 <Java软件结构与数据结构>第一周学习总结 在这学期就已经大二了,也已经步入了学习专业课的核心时间,在这个阶段,我们应该了解自己的学习情况,针对自己 ...