微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Servlet3——特性

Servlet 3.0的注解

Servlet 3.0的显著变化是抛弃了web.xml配置Servlet,Filter和Listener的繁琐步骤,允许开发人员使用注解的方式来配置这些类。
Servlet 3.0规范在javax.servlet.annotation包下提供了如下注解:

  1. @WebServlet:用于修饰一个Servlet类,用于部署Servlet类

  2. @WebInitParam:用于与@WebServlet或@WebFilter一起使用,为Servlet、Filter配置参数

  3. @WebListener:用于修饰一个Listener类,用于部署Listener类

  4. @WebFilter:用于修饰一个Filter类,用于部署Filter类

  5. @MultipartConfig:用于修饰Servlet,指定该Servlet将会负责处理multipart/form-data类型的请求(主要用于文件上传

  6. @ServletSecurity一个与JAAS有关的注解,修饰Servlet指定该Servlet的安全与授权控制

  7. @HttpConstraint:用于与@ServletSecurity一起使用

  8. @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,但多出了两个元素nameordering,具体的配置信息用到了可以查。
将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("异步<a href="https://www.jb51.cc/tag/diaoyong/" target="_blank" class="keywords">调用</a>示例");
        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:

  1. 为@WebServlet指定asyncSupported=true

  2. 在web.xml文件中为servlet元素添加&lt;async-supported&gt;子元素
    另外,还可以对异步线程的执行情况进行监听,通过实现AsyncListener接口来完成。

改进的Servlet API

Servlet 3.0改进了部分API,其中两个比较大的改进是:

HttpServletRequest增加了对文件上传支持
ServletContext允许通过编程的方式动态的注册Servlet、Filter

还是来举个栗子,下边是文件提交页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

    
        <a href="https://www.jb51.cc/tag/wenjian/" target="_blank" class="keywords">文件</a><a href="https://www.jb51.cc/tag/shangchuan/" target="_blank" class="keywords">上传</a>
    
    
        
文件名:
选择文件

处理文件上传的Servlet:

@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() &amp;&amp; (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 举报,一经查实,本站将立刻删除。

相关推荐