Spring及Servlet 3.0的Filter和DispatcherType

Servlet的执行,有五种触发方式:

DispatcherType  = [ ASYNC、ERROR、FORWARD、INCLUDE、REQUEST ]

简单说明:

 1、forward是 应用程序内 Servlet1将请求转发给 另一个 Servlet2继续处理客户请求;

 2、include和forward差不多,区别在于:

  • include方法使原先的Servlet和转发到的Servlet都可以输出响应信息,即原先的Servlet还可以继续输出响应信息。  

  • forward方法调用后在响应中的没有提交的内容被自动消除。将请求转发给其他的Servlet后,由被调用的Servlet负责对请求做出响应,而原先Servlet的执行则终止。   

 3、ASYNC是什么意思呢?下面有个例子:

protected void doGet(HttpServletRequest request,) {
    PrintWriter out = response.getWriter();
    out.print("<h1>hello</h1>");

    // 异步执行,new Thread传递AsyncContext对象并且start
    AsyncContext context = request.startAsync();
    new Thread(new Executor(context)).start();
    
    System.out.println("Servlet执行结束时间:"+new Date());
}

//内部类实现线程
public class Executor implements Runnable{
    private AsyncContext context;
    @Override
    public void run() {
        //执行相关复杂业务
        context.getRequest();
        context.getResponse();
        ServletResponse response = context.getResponse();
        PrintWriter out = response.getWriter();
        out.flush();
        System.out.println("业务完成时间:"+new Date());
    }
}

具体我没看文档,应该是可以把 RequestContext广播给多个异步线程去处理,期间一直保持HTTP连接不释放吧。

那么 ASYNC 很像是 INCLUDE 的升级版,INCLUDE 是 分配任务给另一个 Servlet执行,而ASYNC则可以将任务分配给任意多个普通线程去执行,另外,ASYNC应该可以释放当前Servlet线程(仅保留Connector线程即可),而INCLUDE则会新增另一个Servlet线程,从管理角度有区别(但从性能角度其实差不多吧?)。


Servlet 3.0中,可以 filter过滤器 可以根据DispatcherType的类型选择是否执行。有些请求,会在服务器内部调整或从内部触发,所以Filter可能会执行多次。Spring中所有的Filter都继承了OncePerRequestFilter,为什么呢?

    顾名思义,它能够确保在一次请求只通过一次filter,而不需要重复执行。

    大家常识上都认为,一次请求本来就只过一次,为什么还要由此特别限定呢,实际上我们常识和实际的实现并不真的一样,经过一番查阅后,此方式是为了兼容不同的web container,特意而为之(jsr168),也就是说并不是所有的container都像我们期望的只过滤一次,servlet版本不同,表现也不同。

    在servlet-2.3中,Filter会过滤一切请求,包括服务器内部使用forward转发请求和<%@ include file="/index.jsp"%>的情况。 

    到了servlet-2.4中Filter默认下只拦截外部提交的请求,forward和include这些内部转发都不会被过滤。但是有时候我们需要 forward的时候也用到Filter。 

    因此,为了兼容各种不同的运行环境和版本,默认filter继承OncePerRequestFilter是一个比较稳妥的选择。


    通过Spring的FilterRegistrationBean注册Filter,默认会判断 filter 是否继承于  OncePerRequestFilter,如果是,则无论哪种DispatcherType,该filter都只会执行一次。如果否,则默认设置 DispatcherType = REQUEST。程序员也可以手动设置 DispatcherType,例如:

registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);

但是我还是建议,自己写的filter都继承 Spring的OncePerRequestFilter。


© 2009-2020 Zollty.com 版权所有。渝ICP备20008982号