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


     
    Filter介绍:
        Filter在项目中经常可以用到,通常配置在web.xml中。是服务器端的一个组件,对于用户的请求和响应数据进行过滤操作,控制是否让用户访问到对应的web资源。常用于编码更改、权限控制等操作。
     
    过滤器的执行顺序:
    1333424123_7382.jpg
    配置方式:web.xml
    1. <!--filter过滤器-->
    2. <filter>
    3. <!--filter名称-->
    4. <filter-name>myCharacterFilter</filter-name>
    5. <!--filter处理的类-->
    6. <filter-class>com.filter.MyCharacterFilter</filter-class>
    7. <!--初始化参数-->
    8.     <init-param>
    9. <param-name>defaultCharset</param-name>
    10. <param-value>UTF-8</param-value>
    11. </init-param>
    12. </filter>
    13. <!--过滤器映射-->
    14. <filter-mapping>
    15. <!--和过滤器名相同-->
    16. <filter-name>myCharacterFilter</filter-name>
    17. <!--拦截的路径-->
    18. <url-pattern>*.do</url-pattern>
    19. </filter-mapping>
    20.  
    21. <!--映射多个不同路径,需要些多个<filter-mapping>-->
    22. <filter-mapping>
    23. <filter-name>myCharacterFilter</filter-name>
    24. <url-pattern>*.action</url-pattern>
    25. </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  :
        
        控制台输出日志顺序:
              MyCharacterFilter   start==do
    RoleFilter doFilter  ===  start
    RoleFilter doFilter  ===  end
    MyCharacterFilter   end==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)。配置内容:
    IMG_2134.PNG
     
     
    这里做Demo的时候遇到了点问题,Dynamic Web Module版本是2.5,想改成3.0。发现没法改。(截图是改好的),可以点击右面的Runtimes,里面选择web容器,
    注意此处只有web容器本身能支持servlet3.0才能选择3.0的Dynamic Web Module,比如Tomcat必须选择Tomcat7.0++,选择Apply-OK。然后再进来就能选择3.0了。
     
     
    Servlet3.0特性之filter-dispatcher(ASYNC):
        1.业务逻辑处理之前调用AsyncContext ctx = req.startAsync();
      2.创建线程、传入ctx并调用具体业务逻辑。
      3.调用完成执行ctx的complete()函数。
    Demo:
        ①.配置filter的dispatcher值为ASYNC,servlet的async-supported值为true.
    1. <filter>
    2. <filter-name>roleFilter</filter-name>
    3. <filter-class>com.filter.MyRoleFilter</filter-class>
    4. <init-param>
    5. <param-name>username</param-name>
    6. <param-value>www</param-value>
    7. </init-param>
    8. </filter>
    9. <filter-mapping>
    10. <filter-name>roleFilter</filter-name>
    11. <url-pattern>*.action</url-pattern>
    12. <dispatcher>ASYNC</dispatcher>
    13. </filter-mapping>
    14. <servlet>
    15. <description></description>
    16. <display-name>LoginServlet2</display-name>
    17. <servlet-name>LoginServlet2</servlet-name>
    18. <servlet-class>com.servlet.LoginServlet2</servlet-class>
    19. <async-supported>true</async-supported>
    20. </servlet>
    21. <servlet-mapping>
    22. <servlet-name>LoginServlet2</servlet-name>
    23. <url-pattern>/LoginServlet.action</url-pattern>
    24. </servlet-mapping>
        ②.servlet的处理逻辑中加入req.startAsync()函数,创建一个新的线程传入ctx对象并来执行业务逻辑
    1. resp.setContentType("text/html;charset=UTF-8");
    2. PrintWriter pw = resp.getWriter();
    3. pw.println("进入servlet时间" + new SimpleDateFormat("yyyy-Mm-dd HH:mm:ss").format(new Date()));
    4. pw.flush();
    5. AsyncContext ctx = req.startAsync();
    6. new Thread(new Executor(ctx)).start();
    7. pw.println("离开servlet时间" + new SimpleDateFormat("yyyy-Mm-dd HH:mm:ss").format(new Date()));
    8. pw.flush();
        ③.线程的run()函数执行逻辑后调用ctx的complete()函数通知容器异步处理完成。
    1. //等待10s,模拟业务逻辑
    2. try {
    3. Thread.sleep(10000);
    4. PrintWriter pw = ctx.getResponse().getWriter();
    5. pw.println("业务逻辑处理完成时间"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    6. pw.flush();
    7. this.ctx.complete();
    8. } catch (Exception e) {
    9. e.printStackTrace();
    10. }
       搞定,亲测结果OK。输出结果:
       直接输出(servlet已响应):进入servlet时间2015-1015-19 12:15:46 离开servlet时间2015-1015-19 12:15:46 
      大约10S后输出结果(单独开线程异步处理):业务逻辑处理完成时间2015-10-19 12:15:56
     
    顺便提及servlet3.0的异步处理的监听器AsyncListener,这个接口监控如下4种事件:
    1. 异步线程开始时,调用 AsyncListener 的 onStartAsync(AsyncEvent event) 方法;
    2. 异步线程出错时,调用 AsyncListener 的 onError(AsyncEvent event) 方法;
    3. 异步线程执1333424123_7382.jpg行超时,则调用 AsyncListener 的 onTimeout(AsyncEvent event) 方法;
    4. 异步执行完毕时,调用 AsyncListener 的 onComplete(AsyncEvent event) 方法。 
     
    要注册一个 AsyncListener,只需将准备好的 AsyncListener 对象传递给 AsyncContext 对象的 addListener() 方法即可,如下所示:
    1. ctx.addListener(new AsyncListener() {
    2. @Override
    3. public void onTimeout(AsyncEvent arg0) throws IOException {
    4. System.out.println("listener===超时");
    5. }
    6. @Override
    7. public void onStartAsync(AsyncEvent arg0) throws IOException {
    8. System.out.println("listener===开始");
    9. }
    10. @Override
    11. public void onError(AsyncEvent arg0) throws IOException {
    12. System.out.println("listener===异常");
    13. }
    14. @Override
    15. public void onComplete(AsyncEvent arg0) throws IOException {
    16. System.out.println("listener===完成");
    17. }
    18. });
         经过测试,发现onStartAsync()这个函数没有被调用,没有找到原因!onComplete()正常被调用,onTimeout()debug的时候会打印出超时的信息。
     
     
    IMG_2151.PNG
     
     
     
     
     
     
     
     
     
     
     
     
     
     
            
     





  • 相关阅读:
    广义表的创建和遍历
    dev c++ Boost库的安装
    NAT模式
    vmware桥接模式
    smb与samba
    利用Linux的Samba服务模拟NT域
    使用samba进行共享文件操作步骤
    安装chrome
    使用虚拟机上网第二步
    TCP协议三次握手过程分析
  • 原文地址:https://www.cnblogs.com/douJiangYouTiao888/p/6473936.html
Copyright © 2020-2023  润新知