JSP&Servlet 学习笔记(八)

22,请求封装器

对于容器产生的HttpServletRequest对象,无法直接修改某些信息,如请求参数值就是一个例子。如果实现HttpServletRequest接口,让getParameter()返回

过滤后的请求参数值,HttpServletRequest接口定义的方法都要实现,这相当麻烦。

有个HttpServletRequestWraper实现了HttpServletRequest接口,只要继承HttpServletRequestWrapper类,并编写想要重新定义的方法即可。相对应于ServletRequest接口,

也有个ServletRequestWerapper类可以使用.

23,响应封装器

要实现响应封装器可以继承HttpServletResponseWrapper类对ttpServletResponse对象进行封装。

24,异步处理

Web容器会为每个请求分配一个线程,默认情况下,响应完成前,该线程占用的资源都不会被释放。若有些请求需要长时间处理,

就会长时间占用线程所需资源,若此类请求很多,许多线程资源都被长时间占用,会对系统的性能造成负担。

Servlet3.0新增了异步处理,可以先释放容器分配给请求的线程与相关资源,减轻系统负担,原先释放了容器所分配线程的请求,其响应将被延后,可以在

处理完成时在对客户端进行响应。

为了支持异步处理,在Servlet3.0中,在ServletRequest上提供了startAsync()方法:

AsyncContext startAsync() throws java.lang.IllegalStateException;

AsyncContext startAsync(ServletRequest servletRequest,ServletResponse servletResponse) throws java.lang.IllegalStateException;

这两个方法都会返回AsyncContext接口的实现对象,前者会直接利用原有的请求与响应对象来创建AsyncContext,后者可以传入自行创建的请求,响应封装对象。

在调用了startAsync()方法取得AsyncContext对象之后,此次请求的响应会被延后,并释放容器分配的线程。

可以通过AsyncContext的getRequest(),getResponse()方法取得请求,响应对象,此次对客户端的响应将暂缓至调用AsyncContext的complete()或dispatch()方法为止,

前者表示响应完成,后者表示将调派指定的URL进行响应。

若能调用ServletRequest的startAsync()以取得AsyncContext,必须告知容器此Servlet支持异步处理,如果使用@WebServlet来标注,则可以设置asyncSupported为true。

如果Servlet将会进行异步处理,若其前端有过滤器,则过滤器亦需标示其支持异步处理,如果使用@WebFilter,同样可以设置其asyncSupported为true。

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name="AsyncServlet",urlPatterns={"/async.do"},
asyncSupported=true)//告诉容器此Servlet支持异步处理
public class AsyncServlet extends HttpServlet{
private ExecutorService executorService=Executors.newFixedThreadPool(10);

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
super.doGet(req, resp);
resp.setContentType("text/html; charset=UTF8");
AsyncContext ctx=req.startAsync();//开始异步处理,释放请求线程
executorService.submit(new AsyncRequest(ctx));//创建AsyncRequest,调度线程
}

@Override
public void destroy() {
// TODO Auto-generated method stub
super.destroy();
executorService.shutdown();
}

}

首先告诉容器,这个Servlet支持异步处理,对于每个请求,Servlet会取得其AsyncContext,并释放容器所分配的线程,响应被延后。对于这些被延后响应的请求,

创建一个实现Runnable接口的AsyncRequest对象,并将其调度一个线程池(Threadpool),线程池的线程数量是固定的,让这些必须长时间处理的请求,在这些有限数量

的线程中完成,而不用每次请求都占用容器分配的线程。

import java.io.PrintWriter;

import javax.servlet.AsyncContext;

public class AsyncRequest implements Runnable{
private AsyncContext ctx;

public AsyncRequest(AsyncContext ctx){
this.ctx=ctx;
}

@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(10000);
PrintWriter out=ctx.getResponse().getWriter();
ctx.complete();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e);
}


}

}

25,更多AsyncContext细节

如果Servlet或过滤器的asyncSupported被标示为True,则它们支持异步请求处理,在不支持异步处理的Servlet或过滤器中调用startAsync(),会抛出

IllegalStateException。

当在支持异步处理的Servlet或过滤器中调用请求对象的startAsync()方法时,该次请求会离开容器所分配的线程,这意味着必须响应处理流程会返回,也就是

若有过滤器,也会依序返回(也就是完成各自FilterChain的doFilter()方法),但最终的响应被延迟。

可以调用AsyncContext的complete()方法完成响应,而后调用forward()方法,将相应转发给别的Servlet/JSP处理,AsyncContext的forward()将请求的响应权派送给别的

页面来处理,给定的路径时相对于ServletContext的路径。不可以自行在同一个AsyncContext上同时调用complete()与forward(0,否则会抛出IllegalStateException。

不可以在两个异步处理的Servlet间派送前,连续调用两次startAsync(),否则会抛出IllegalStateException。

将请求从支持异步处理的Servlet派送至一个同步处理Servlet是可行的,此时,容器会负责调用AsyncContext的complete()。

如果从一个同步处理的Servlet派送请求至一个支持异步处理的Servlet,在异步处理的Servlet中调用startAsync,会抛出IllegalStateException。

若对AsyncContext的起始,完成,超时或错误发生等事件有兴趣,可以实现AsyncListener。其定义如下:

package javax.servlet;

// Compiled from AsyncListener.java (version 1.7 : 51.0, no super bit)
public abstract interface javax.servlet.AsyncListener extends java.util.EventListener {

// Method descriptor #5 (Ljavax/servlet/AsyncEvent;)V
public abstract void onComplete(javax.servlet.AsyncEvent arg0) throws java.io.IOException;

// Method descriptor #5 (Ljavax/servlet/AsyncEvent;)V
public abstract void onTimeout(javax.servlet.AsyncEvent arg0) throws java.io.IOException;

// Method descriptor #5 (Ljavax/servlet/AsyncEvent;)V
public abstract void onError(javax.servlet.AsyncEvent arg0) throws java.io.IOException;

// Method descriptor #5 (Ljavax/servlet/AsyncEvent;)V
public abstract void onStartAsync(javax.servlet.AsyncEvent arg0) throws java.io.IOException;
}

AsyncContext有个addListener()方法,可以加入AsyncListener的实现对象,在对应事件发生时会调用AsyncListener实现对象的对应方法。

如果调用AsynccContext()的dispatch(),将请求调派给别的Servlet,则可以通过请求对象的getAttribute()取得以下属性:

javax.servlet.async.request_uri

javax.servlet.async.context_path

javax.servlet.async.servlet_path

javax.servlet.async.path_info

javax.servlet.async.query_string

其值分别等于调用HttpServletReuqest的getRequestURI(),getContextPath(),getServletPath(),getPathInfo()与getQueryString()所取得结果。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值