Servlet API是Java开发人员最熟悉的API之一,Servlet在1999年所发布的J2SE1.2版本中首次面世,Servlet在JavaWEB的开发中发挥着重要的作用。JavaEE8对Servlet4.0进行了重要的更新。其中服务器推送是最主要的更新,如果要使用服务器推送的功能,则我们必须使用HTTP/2.0版本的协议。JavaEE8提供了对Servlet映射的运行时发现,在运行时我们可以获取Servlet的名称,Servlet的映射路径。JavaEE8简化了对Filter的开发。
本案例开发环境:jdk8,tomcat9,tomcat-native,openssl
Servlet4.0是使用HTTP/2协议,而Tomcat9下载后,默认使用的是HTTP/1.1,所以我们要先修改server.xml配置文件:
1.注释原有的默认使用HTTP/1.1方式
<!--
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
-->
2.开启HTTP2的注释
注意:要删除certificateChainFile这一行,HTTP2使用的端口不在是8080,而是8443,使用HTTP2需要配置一个私钥文件和一个证书文件。
<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="150" SSLEnabled="true" >
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig>
<Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
certificateFile="conf/localhost-rsa-cert.pem"
type="RSA" />
</SSLHostConfig>
</Connector>
关于上面Certificate标签有关说明:当你申请证书时或获取一个证书crt和一个私钥key文件,certificateKeyFile放的就是你的证书key文件,certificateFile则是私钥cert文件,默认放在Tomcat9的conf目录下。
certificateChainFile:一般操作系统/浏览器会内置一些CA(证书颁发机构)的证书,如果你的证书是直接由这些内置CA颁发的,那么就不需要Chain文件,浏览器可以直接识别你的证书。如果你的证书是由二级CA颁发的,即内置CA颁发给另一个二级CA,然后二级CA在颁发给你,那么就需要Chain文件,否则浏览器就不知道你的证书和内置CA的关系。如果你将自记得CA设置成了内置CA,那么直接由你的CA颁发的证书自然不需要Chain文件。
3.生成证书和私钥文件
下载windows openssl:window openssal下载地址
现在我们需要生成server.xml配置中的证书和私钥文件,在这里我是使用openssl生成的,由于windows64是兼容windows32的,所以不必担心不能使用的问题。解压开后,进入bin目录,启动openssl.exe
使用管理权限执行以下命令,生成私钥:
OpenSSL> genrsa -out localhost-rsa-key.pem 1024
使用配置文件生成证书(可以填写相关的组织信息):
req -new -key localhost-rsa-key.pem -x509 -days 3650 -config "C:\Program Files\OpenSSL-Win64\bin\cnf\openssl.cnf" -out localhost-rsa-cert.pem
将第三步生成了两个文件,放入tomcat9的conf目录下。
4.下载tomcat-nativate
tomcat-native下载地址:tomcat-native
下载tomcat-nativate文件并解压,如果你是win32系统直接将bin目录下tcnative-1.dll和tcnative-1-src.pdb文件复制到jdk的bin目录下,如果你是win64则将x64文件下的这两个文件复制到jdk目录下。
至此我们已经完成了Tomcat9的HTTP协议的升级,现在你可以启动Tomcat9,然后访问https://localhost:8443/即可看到tomcat页面。

5.测试服务推送 将用户所需的WEB资源提前推送到用户的浏览器缓存中,当用户使用浏览器访问所需WEB资源时,用户不需要再次下载所需的资源,因为用户所需的WEB资源已经存在与用户的浏览器缓存中。
Servlet4.0通过PushBuilder接口公开服务器推送。为了能够进行访问,你需要通过调用newPushBuilder()方法,从HttpServletRequest获取PushBuilder实例。
测试使用服务推送把两张图片资源推送到浏览器缓存。
编写Servlet测试服务推送。
/**
* 将用户所需的WEB资源提前推送到用户的浏览器缓存中,当用户使用浏览器访问所需WEB资源时,
* 用户不需要再次下载所需的资源,因为用户所需的WEB资源已经存在与用户的浏览器缓存中。
*/
@WebServlet("/PushServlet")
public class PushServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PushBuilder pushBuilder = req.newPushBuilder();
if (pushBuilder != null) {
PushBuilder path = pushBuilder.path("./images/hello.jpg");
path.push();
// 只推送最后一个path里的资源
//PushBuilder path = pushBuilder.path("./hey.jpg").path("./hello.jpg");
//path.push();
// 推送多个资源的写法
//pushBuilder.path("./hello.jpg").push();
//pushBuilder.path("./hey.jpg").push();
}
req.getRequestDispatcher("test.html").forward(req, resp);
}
}
请求转发后的静态页面:
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
</head>
<body>
Hello
<p>
<img src="images/hello.jpg" alt="first">
<img src="images/hey.jpg" alt="second">
</p>
</body>
</html>
使用服务器推送,效果很明显,不需要向服务器二次请求建立连接,因为图片在建立Servlet链接请求的时候,服务器端就已经推送过来了,所以在PushServlet时可以看到,这张图比不使用服务推送多耗了一点时间,因为要多下载一张图。总体上相当于省下了hey.jpg建立链接的时间。