2.13 Servlet3.1新增的非阻塞式IO
2.13 Servlet3.1新增的非阻塞式IO
最新的Java EE 7已经发布,伴随Java EE 7一起发布了Servlet3.1,Servlet3.1引入了少数新特性。Servlet3.1新特性包括强制更改sessionId(由HttpServletRequest的changeSessionId()方法提供)、非阻塞IO等。尤其是Servlet3.1提供的非阻塞IO进行输入、输出,可以更好地提升性能。Servlet底层的IO是通过如下两个IO流来支持的。
ServletInputStream:Servlet用于读取数据的输入流。ServletOutputStream:Servlet用于输出数据的输出流。
以Servlet读取数据为例,传统的读取方式采用阻塞式IO——当Servlet读取浏览器提交的数据时,如果数据暂时不可用,或数据没有读取完成,Servlet当前所在线程将会被阻塞,无法继续向下执行。
ReadListener
从Servlet3.1开始,ServletInputStream新增了一个setReadListener(ReadListener readListener)方法,该方法允许以非阻塞IO读取数据,实现ReadListener监听器需要实现如下三个方法
onAllDataRead():当所有数据读取完成时激发该方法。onDataAvailable():当有数据可用时激发该方法onError(Throwable t):读取数据出现错误时激发该方法。
类似地,ServletOuputStream也提供了setWriterListenerer(WriteListener writeListener)方法,通过这种方式,可以让ServletOuputStream以非阻塞IO进行输出
Servlet中使用非阻塞IO步骤
在Servlet中使用非阻塞IO非常简单,主要按如下步骤进行即可:
- 调用
ServletRequest的startAsync()方法开启异步模式 - 通过
ServletRequest获取ServletInputStream,并为ServletInputStream设置监听器(ReadListener实现类)。 - 实现
ReadListener接口来实现监听器,在该监听器的方法中以非阻塞方式读取数据。
程序示例
项目结构
G:\Desktop\随书源码\轻量级Java EE企业应用实战(第5版)\codes\02\2.13\servlet31 ├─async.jsp ├─form.html └─WEB-INF\ ├─build.xml ├─classes\ │ └─lee\ │ ├─AsyncServlet.class │ └─MyReadListener.class ├─lib\ ├─src\ │ └─lee\ │ ├─AsyncServlet.java │ └─MyReadListener.java └─web.xml
下面的Servlet负责处理表单页面提交的数据,但该Servlet并未使用传统的、阻塞IO来读取客户端数据,而是采用非阻塞IO进行读取。下面是该Servlet的代码。
AsyncServlet.java
1 | package lee; |
上面程序调用request的startAsync()方法开启异步调用之后,程序中粗体字代码为Servlet输入流注册了一个监听器,这样就无须在该Servlet中使用阻塞IO来获取数据了。而是改为由MyReadListener负责读取数据,这样Servlet就可以继续向下执行,不会因为IO阻塞线程。MyReadListener需要实现Readlistener接口,并重写它的三个方法。
MyReadListener.java
下面是MyReadListener的代码。
1 | package lee; |
上面程序中MyReadListener的onDataAvailable()方法先暂停线程5秒,用于模拟耗时操作,接下来程序使用普通IO流读取浏览器提交的数据。
如果程序直接让Servlet读取浏览器提交的数据,那么该Servlet就需要阻塞5秒,不能继续向下执行;改为使用非阻塞IO进行读取,虽然读取数据的IO操作需要5秒,但它不会阻塞Servlet执行,因此可以提升Servlet的性能。
程序使用一个简单的表单向该Servlet提交请求,该表单内包含了请求数据。提交的表单效果如图2.53所示。