Servlet 3.0的注解
Servlet 3.0的显著变化是抛弃了web.xml配置Servlet,Filter和Listener的繁琐步骤,允许开发人员使用注解的方式来配置这些类。
Servlet 3.0规范在javax.servlet.annotation包下提供了如下注解:
@WebServlet
:用于修饰一个Servlet类,用于部署Servlet类@WebInitParam
:用于与@WebServlet或@WebFilter一起使用,为Servlet、Filter配置参数@WebListener
:用于修饰一个Listener类,用于部署Listener类@WebFilter
:用于修饰一个Filter类,用于部署Filter类@MultipartConfig
:用于修饰Servlet,指定该Servlet将会负责处理multipart/form-data类型的请求(主要用于文件上传)@HttpConstraint
:用于与@ServletSecurity一起使用@HttpMethodConstraint
:用于与@ServletSecurity一起使用
Servlet 3.0的Web模块化支持
Servlet3.0规范不在要求所有的Web组件(如Servlet、Filter和Listener)多必须定义在web.xml文件中,而是允许采用“Web模块”来部署、管理他们。
一个web模块通常是对应一个jar包,jar包的格式如下:
webmodule.jar
|--meta-inf
| |--web-fragment.xml
|--Web模块所用的类文件、资源文件等
配置文件web-fragment.xml的格式类似于web.xml,但多出了两个元素name
和ordering
,具体的配置信息用到了可以查。
将web模块化对应的jar包复制到任意web应用下的WEB-INF/lib目录下,启动web应用就可以了。
Servlet 3.0提供的异步处理
在以前的Servlet规范中,如果Servlet作为控制器调用了一个费时的操作,那么Servlet就必须等到业务方法执行完毕之后才生成响应。在Servlet3.0中,异步处理允许Servlet重新发起一条新的线程去调用耗时的业务方法,这样就避免了用户等待。
实现方式是通过AsyncContext类来处理的,Servlet可通过ServletRequest的如下两个方法开启异步调用、创建AsyncContext对象。
AsyncContext startAsync()
AsyncContext startAsync(ServletRequest,ServletResponse)
重复调用上边的方法得到的都是同一个AsyncContext对象
。AsyncContext对象代表异步处理的上下文,提供了一些工具方法,可完成设置异步调用的超时时间,dispatch用于请求、启动后台线程、获取request、response对象等功能。
咱们来举个栗子来说明一下,下边是一个异步处理的Servlet类:
@WebServlet(urlPatterns = "/async",name = "async",asyncSupported = true)
public class AsyncServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req,HttpServletResponse resp) throws servletexception,IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("异步调用示例 ");
out.println("进入Servlet的时间是:"+new Date()+"
");
//创建AsyncContext,开始异步调用
AsyncContext asyncContext = req.startAsync();
//设置异步调用的超时时间
asyncContext.setTimeout(60*1000);
//启动异步调用的线程
asyncContext.start(new GetBookTarget(asyncContext));
out.println("结束Servlet的时间是:" + new Date() + "
");
out.flush();
}
}
GetBookTarget类表示如下:
public class GetBookTarget implements Runnable{
private AsyncContext asyncContext;
public GetBookTarget(AsyncContext asyncContext){
this.asyncContext = asyncContext;
}
@Override
public void run() {
try{
Thread.sleep(5*1000);
ServletRequest request = asyncContext.getRequest();
ArrayList<String> books = new ArrayList<>();
books.add("权利的游戏");
books.add("列王的纷争");
books.add("冰雨的风暴");
request.setAttribute("a",books);
asyncContext.<a href="https://www.jb51.cc/tag/dis/" target="_blank" class="keywords">dis</a>patch("/jsp/Async.jsp");
}catch (Exception e){
e.<a href="https://www.jb51.cc/tag/printstacktrace/" target="_blank" class="keywords">printstacktrace</a>();
}
}
}
Async.jsp的内容如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" session="false" %>
<%@ taglib prefix="mytag" tagdir="/WEB-INF/tags" %>
<%
out.println("业务调用结束的时间"+new Date());
if (request.isAsyncStarted()){
request.getAsyncContext().complete();
}
%>
有两种方式来启用异步的Servlet:
为@WebServlet指定
asyncSupported=true
在web.xml文件中为servlet元素添加
<async-supported>
子元素
另外,还可以对异步线程的执行情况进行监听,通过实现AsyncListener接口来完成。
改进的Servlet API
Servlet 3.0改进了部分API,其中两个比较大的改进是:
HttpServletRequest增加了对文件上传的支持
ServletContext允许通过编程的方式动态的注册Servlet、Filter
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
文件上传
@WebServlet(name = "upload",urlPatterns = {"/upload"})
@MultipartConfig
public class Upload extends HttpServlet {
@Override
public void service(ServletRequest req,ServletResponse res) throws servletexception,IOException {
res.setContentType("text/html;charset=utf-8");
PrintWriter out = res.getWriter();
req.setCharacterEncoding("utf-8");
String name = req.getParameter("filename");
out.println("普通的name参数为:"+name+"
");
HttpServletRequest httpServletRequest = (HttpServletRequest)req;
//获取文件上传域
Part part = httpServletRequest.getPart("file");
out.println("文件上传的类型:"+part.getContentType()+"
");
out.println("文件上传的大小:"+part.getSize()+"
");
//获取该文件上传域的Header Name
Collection headerNames = part.getHeaderNames();
for (String headerName : headerNames){
out.println(headerName+"----->"+part.getHeader(headerName)+"
");
}
out.println("文件名:"+part.getSubmittedFileName());
part.write(getServletContext().getRealPath("/uploadFiles")+"/"+part.getSubmittedFileName());
}
}
Servlet 3.1新增的非阻塞式IO
伴随Java EE7一起发布了Servlet3.1,Servlet3.1引入了不少新特性。尤其是Servlet3.1提供的非阻塞IO进行输入、输出,可以更好地提升性能。
以Servlet读取数据为例,传统的读取方式采用阻塞式IO——当Servlet读取浏览器提交的数据时,如果数据暂时不可用,或者数据没有读取完成,Servlet当前所在的线程会被阻塞,无法继续向下执行。Servlet3.1开始,ServletInputStream新增了一个setReadListener(ReadListener listener)方法,该方法允许以非阻塞IO读取数据,实现ReadListener监听器需要实现如下三个方法:
onAllDataRead():当所有数据读取完成时激发该方法。
onDataAvailable():当有数据可用时激发该方法。
OnError():读取数据出现错误时激发该方法。
下边来举个栗子:
@WebServlet(urlPatterns = "/asyncio",name = "asyncio",asyncSupported = true)
public class AsyncServlet3_1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req,IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("非阻塞IO示例 ");
out.println("进入Servlet的时间:"+new Date()+"
");
//创建AsyncContext,开始异步调用
AsyncContext asyncContext = req.startAsync();
//设置异步调用的超时时长
asyncContext.setTimeout(30*1000);
ServletInputStream inputStream= req.getInputStream();
inputStream.setReadListener(new AsyncIOListener(asyncContext,inputStream));
out.println("结束Servlet的时间:" + new Date() + "
");
out.flush();
}
}
AsyncIOListener的代码如下:
public class AsyncIOListener implements ReadListener {
private ServletInputStream inputStream;
private AsyncContext asyncContext;
public AsyncIOListener(AsyncContext asyncContext,ServletInputStream inputStream){
this.inputStream = inputStream;
this.asyncContext = asyncContext;
}
@Override
public void onDataAvailable() throws IOException {
Sy<a href="https://www.jb51.cc/tag/stem/" target="_blank" class="keywords">stem</a>.out.println("数据可用!");
try {
Thread.sleep(2*1000);
StringBuffer sb = new StringBuffer();
int len = -1;
byte[] buffer = new byte[1024];
while (inputStream.isReady() && (len = inputStream.read(buffer)) > 0){
String data = new String(buffer,len);
sb.append(data);
}
Sy<a href="https://www.jb51.cc/tag/stem/" target="_blank" class="keywords">stem</a>.out.println(sb);
asyncContext.getRequest().setAttribute("info",sb.toString());
//转发到视图<a href="https://www.jb51.cc/tag/yemian/" target="_blank" class="keywords">页面</a>,原理类似于forward
asyncContext.<a href="https://www.jb51.cc/tag/dis/" target="_blank" class="keywords">dis</a>patch("/jsp/Async3_1.jsp");
}catch (Exception e){
e.<a href="https://www.jb51.cc/tag/printstacktrace/" target="_blank" class="keywords">printstacktrace</a>();
}
}
@Override
public void onAllDataRead() throws IOException {
Sy<a href="https://www.jb51.cc/tag/stem/" target="_blank" class="keywords">stem</a>.out.println("请求数据读取完成");
}
@Override
public void onError(Throwable throwable) {
Sy<a href="https://www.jb51.cc/tag/stem/" target="_blank" class="keywords">stem</a>.out.println("读取请求数据出错");
}
}
Async3_1.jsp的代码如下所示:
<%@ page contentType="text/html;charset=UTF-8" language="java" session="false" %>
<%out.println("业务调用结束的时间:"+new Date());%>
<%
if (request.isAsyncStarted()){
request.getAsyncContext().complete();
}
%>
Tomcat8的WebScoket支持
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。