您的位置:首页 > 其它

Filter学习总结,顺便提及点servlet3.0异步filter和异步监听

2017-02-27 14:29 330 查看
Filter介绍:
Filter在项目中经常可以用到,通常配置在web.xml中。是服务器端的一个组件,对于用户的请求和响应数据进行过滤操作,控制是否让用户访问到对应的web资源。常用于编码更改、权限控制等操作。

过滤器的执行顺序:



配置方式:web.xml

<!--filter过滤器-->


<filter>


<!--filter名称-->


<filter-name>myCharacterFilter</filter-name>


<!--filter处理的类-->


<filter-class>com.filter.MyCharacterFilter</filter-class>


<!--初始化参数-->


<init-param>


<param-name>defaultCharset</param-name>


<param-value>UTF-8</param-value>


</init-param>


</filter>


<!--过滤器映射-->


<filter-mapping>


<!--和过滤器名相同-->

<filter-name>myCharacterFilter</filter-name>


<!--拦截的路径-->


<url-pattern>*.do</url-pattern>


</filter-mapping>




<!--映射多个不同路径,需要些多个<filter-mapping>-->


<filter-mapping>


<filter-name>myCharacterFilter</filter-name>


<url-pattern>*.action</url-pattern>


</filter-mapping>


<filter>和<filter-mapping>的<filter-name>必须相同,多个不同路径需配置多个不同的<filter-mapping>。
初始化参数可以写到<filter>的子节点<init-param>中,配置为键值对的方式,即<param-name>、<param-value>。
Filter的实现类需要实现javax.servlet.Filter接口,默认重写init()、destroy()、doFilter()函数,这3个函数分别对应初始化、销毁、过滤这3个生命周期。

生命周期:
实例化:web容器在部署web应用程序时对所有过滤器进行实例化。web容器回调它的无参构造方法。
初始化:启动服务器时加载过滤器的实例,并自动调用init()函数。
过滤:调用过滤器的doFilter()执行过滤,这个是过滤器的核心方法。
销毁:停止服务时调用destroy()函数,销毁过滤器实例。

初始化参数获取:
通过init()函数的参数FilterConfig对象,filter.getInitParameter("初始化参数key")能拿到初始化参数。

过滤器链:
过滤器可以在web.xml中配置多个,满足对某一URL进行过滤条件时,会按照web.xml中配置的顺序进行执行,构成过滤器链。举例如下:

请求某一URL执行过滤器MyCharacterFilter和MyRoleFilter。MyCharacterFilter执行后会调用filterChain.doFilter()方法继续调用MyRoleFilter过滤器。
MyCharacterFilter:



MyRoleFilter:



控制台输出日志顺序:

MyCharacterFilterstart==do

RoleFilterdoFilter===start
RoleFilterdoFilter===end
MyCharacterFilterend==do


<filter-mapping>的特殊参数-dispatcher:
此参数根据配置不同,支持不同类型的请求,可配置多个。
REQUEST(默认值):从客户端直接请求过来会走这个过滤器,直接请求或redirect.sendRedirect("url");。

FORWEARD:通过dispatcher的forward方法会走这个过滤器。request.getdispatcher("url").forward(request,response);或使用jsp指令jsp:forward。

INCLUDE:通过dispatcher的include()方法会走这个过滤器。request.getdispatcher("url").include(request,response);或使用jsp指令jspinclude。

ERROR:通过web.xml中<error-page>过来的请求会走这个过滤器。
ASYNCServlet3.0添加了对另一种值的支持:异步处理)。原有的servlet需要处理完业务逻辑再相应,现在会开启另外一个线程单独处理业务逻辑,servlet线程委托其他线程处理业务逻辑,自己在不生成响应的情况下返回至容器,提高并发访问速度,减少服务器资源的占用。(下面有Demo)

Servlet3.0增加了对注解的支持,可以通过注解配置,不用在web.xml中配置。需要配合支持Tomcat7.0以上容器(支持servlet3.0)。配置内容:



这里做Demo的时候遇到了点问题,DynamicWebModule版本是2.5,想改成3.0。发现没法改。(截图是改好的),可以点击右面的Runtimes,里面选择web容器,
注意此处只有web容器本身能支持servlet3.0才能选择3.0的DynamicWebModule,比如Tomcat必须选择Tomcat7.0++,选择Apply-OK。然后再进来就能选择3.0了。



Servlet3.0特性之filter-dispatcher(ASYNC):
1.业务逻辑处理之前调用AsyncContextctx=req.startAsync();
2.创建线程、传入ctx并调用具体业务逻辑。

3.调用完成执行ctx的complete()函数。

Demo:
①.配置filter的dispatcher值为ASYNC,servlet的async-supported值为true.

<filter>


<filter-name>roleFilter</filter-name>


<filter-class>com.filter.MyRoleFilter</filter-class>


<init-param>


<param-name>username</param-name>


<param-value>www</param-value>


</init-param>


</filter>


<filter-mapping>


<filter-name>roleFilter</filter-name>


<url-pattern>*.action</url-pattern>


<dispatcher>ASYNC</dispatcher>


</filter-mapping>


<servlet>


<description></description>


<display-name>LoginServlet2</display-name>


<servlet-name>LoginServlet2</servlet-name>


<servlet-class>com.servlet.LoginServlet2</servlet-class>


<async-supported>true</async-supported>


</servlet>


<servlet-mapping>


<servlet-name>LoginServlet2</servlet-name>


<url-pattern>/LoginServlet.action</url-pattern>


</servlet-mapping>


②.servlet的处理逻辑中加入req.startAsync()函数,创建一个新的线程传入ctx对象并来执行业务逻辑。

resp.setContentType("text/html;charset=UTF-8");


PrintWriterpw=resp.getWriter();


pw.println("进入servlet时间"+newSimpleDateFormat("yyyy-Mm-ddHH:mm:ss").format(newDate()));


pw.flush();


AsyncContextctx=req.startAsync();


newThread(newExecutor(ctx)).start();


pw.println("离开servlet时间"+newSimpleDateFormat("yyyy-Mm-ddHH:mm:ss").format(newDate()));


pw.flush();


③.线程的run()函数执行逻辑后调用ctx的complete()函数通知容器异步处理完成。

//等待10s,模拟业务逻辑


try{


Thread.sleep(10000);


	PrintWriterpw=ctx.getResponse().getWriter();


	pw.println("业务逻辑处理完成时间"+newSimpleDateFormat("yyyy-MM-ddHH:mm:ss").format(newDate()));


pw.flush();


this.ctx.complete();


}catch(Exceptione){


e.printStackTrace();


}


搞定,亲测结果OK。输出结果:
直接输出(servlet已响应):进入servlet时间2015-1015-1912:15:46离开servlet时间2015-1015-1912:15:46
大约10S后输出结果(单独开线程异步处理):业务逻辑处理完成时间2015-10-1912:15:56

顺便提及servlet3.0的异步处理的监听器AsyncListener,这个接口监控如下4种事件:

异步线程开始时,调用AsyncListener的onStartAsync(AsyncEventevent)方法;

异步线程出错时,调用AsyncListener的onError(AsyncEventevent)方法;

异步线程执

行超时,则调用AsyncListener的onTimeout(AsyncEventevent)方法;

异步执行完毕时,调用AsyncListener的onComplete(AsyncEventevent)方法。

要注册一个AsyncListener,只需将准备好的AsyncListener对象传递给AsyncContext对象的addListener()方法即可,如下所示:

ctx.addListener(newAsyncListener(){


@Override


			publicvoidonTimeout(AsyncEventarg0)throwsIOException{


System.out.println("listener===超时");


}


@Override


			publicvoidonStartAsync(AsyncEventarg0)throwsIOException{


System.out.println("listener===开始");


}


@Override


			publicvoidonError(AsyncEventarg0)throwsIOException{


System.out.println("listener===异常");


}


@Override


			publicvoidonComplete(AsyncEventarg0)throwsIOException{


System.out.println("listener===完成");


}


});


经过测试,发现onStartAsync()现这个函数没有被调用,没有找到原因!onComplete()正常被调用,onTimeout()debug的时候会打印出超时的信息。



来自为知笔记(Wiz)

附件列表

1333424123_7382.jpg

IMG_2134.PNG

IMG_2151.PNG
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
章节导航