JavaWeb高级编程(九)—— 使用过滤器改进应用程序

本文详细介绍了JavaWeb中的过滤器,包括过滤器的工作原理、创建、声明和映射,以及过滤器排序。通过示例展示了如何使用部署描述符、注解和编程式配置过滤器。此外,还探讨了过滤器的实际应用,如日志记录、压缩响应内容和简化登录认证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、了解过滤器

        过滤器是可以拦截访问资源的请求、资源的响应或者同时拦截两者的应用组件,它们将以某种方式作用于这些请求或响应。过滤器可以检测和修改请求或响应,它们甚至可以拒绝、重定向或转发请求。如同Servlet一样,过滤器可以在部署描述符中以编程或者声明的方式进行声明,它们可以有初始化参数,并且可以访问ServletContext。

二、创建、声明、映射过滤器

        过滤器在初始化时将调用init方法,它可以访问过滤器的配置、初始化参数和ServletContext。当请求进入到过滤器中时,doFilter方法将会被调用,在doFilter之中,可以拒绝请求或者调用FilterChain对象的doFilter方法;可以修改请求或响应;可以封装请求或响应对象。应用程序在关闭时,将调用过滤器的destroy方法。

1、了解过滤器链

        尽管只有一个Servlet可以处理请求,但可以使用许多过滤器拦截请求。调用FilterChain.doFilter()方法将触发过滤器链的持续执行,如果当前处理器是过滤器链的最后一个过滤器,那么调用FilterChain.doFilter()方法将把控制权返回到Servlet容器中,它将把请求传递给Servlet。如果当前的过滤器没有调用FilterChain.doFilter()方法,那么过滤器链将会被中断,Servlet和所有剩余的过滤器都无法再处理该请求。

过滤器链的工作原理:

        过滤器链的这种工作方式非常像栈(确实,一系列方法的执行都运行在Java栈上)。当请求来临时,它将首先进入第一个过滤器,该过滤器将被添加到栈中。当过滤器链继续执行时,下一个过滤器将被添加到栈中。一直到请求进入到Servlet中,它是被添加到栈中的最后一个元素。当请求完成并且Servlet的service方法也返回时,Servlet将从栈中移除,然后控制权被返回到最后一个过滤器,当它的doFilter方法返回时,该过滤器将从栈中移除,控制也将返回到之前的过滤器中。一直到控制权返回到第一个过滤器中,当它的doFilter方法也返回时,它将被从栈中移除,此时栈是空的,请求处理也就完成了。因此,过滤器可以在目标Servlet处理请求的前后执行某些操作。

2、映射到URL模式和Servle名称

        同Servlet一样,过滤器可以映射到URL模式,这会决定哪个或哪些过滤器拦截某个请求。任何匹配某个过滤器的URL模式的请求在被匹配的Servlet处理之前将首先进入该过滤器。通过使用URL模式,我们不止可以拦截Servlet的请求,还可以拦截其他资源,例如图片、CSS文件、JavaScript文件等。

        与映射到URL上相反,我们可以把它映射到一个或多个Servlet名称,如果请求匹配于某个Servlet,容器将寻找所有匹配该Servlet名称的过滤器,并将它们应用到请求上。

3、映射到不同的请求派发器类型

① 普通请求

        这些请求来自于客户端,并包含了容器中特定Web应用程序的目标URL;

② 转发请求

        当代码调用RequestDispatcher的forward方法或者使用<jsp:forward>标签时将触发这些请求;

③ 包含请求

        使用<jsp:include>标签或者调用RequestDispatcher的include方法时,将会产生一个不同的、与原始请求相关的内部请求;

④ 错误资源请求

        这些是访问处理HTTP错误的错误页面的请求。

④ 异步请求

        这些请求是在处理任何其他请求的过程中,由AsyncContext派发的请求。

注意:在Servlet3.0中,Servlet的service方法将在请求的响应发送之前返回,所以过滤器链的能力受到了损害。为了作出补偿,Servlet3.0为AsyncContext派发的过滤器拦截请求添加了新的异步派发类型。实现异步过滤器要小心,因为它们可以被单个异步请求调用多次(多个不同的线程)。

4、使用部署描述符配置过滤器

        下面看一个简单的过滤器在部署描述符中的配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
         id="WebApp_ID" version="3.1">
  <filter>
    <filter-name>myFilter</filter-name>
    <filter-class>com.mengfei.hellofilter.filter.MyFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>myFilter</filter-name>
    <url-pattern>/do/*</url-pattern>
    <url-pattern>/bur</url-pattern>
    <servlet-name>myServlet</servlet-name>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ASYNC</dispatcher>
  </filter-mapping>
  
  <servlet>
    <servlet-name>myServlet</servlet-name>
    <servlet-class>com.mengfei.hellofilter.servlet.MyServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>myServlet</servlet-name>
    <url-pattern>/index</url-pattern>
  </servlet-mapping>
</web-app>

        此时,过滤器会处理所有相对于应用程序的URL——/do/*和/bur的请求,以及任何最终由myServlet处理的请求。有效的<dispatcher>类型有REQUEST、FORWARD、INCLUDE、ERROR、ASYNC,过滤器可以映射0个或多个<dispatcher>元素,如果没有指定,那么默认的就是REQUEST。

        与Servlet不同的是,过滤器不可以在第一个请求到达时加载,过滤器的init()方法总是在应用程序启动时调用,在ServletContextListener初始化之后,Servlet初始化之前,它们将按照部署描述符中出现的顺序依次加载。 

5、使用注解配置过滤器

    &

Resource Page Description 在以前的文章中,我曾多次强调应用程序中异步化的重要性。尤其对于IO密集型操作,异步执行对于应用程序的响应能力和伸缩性有非常关键的影响。正确使用异步编程能够使用尽可能少的线程来执行大量的IO密集型操作。可惜的是,即时异步编程有避免线程阻塞等诸多好处,但是这种编程方式至今没有被大量采用。其原因有很多,其中最主要的一点可能就是异步模型在编程较为困难,导致许多开发人员不愿意去做。 异步,则意味着一个任务至少要被拆分为“二段式”的调用方式:一个方法用于发起异步请求,另一个方法用于异步任务完成后的回调。与传统方法调用方式相比,异步调用时的中间数据不能存放在线程栈上,方法之间的也不能简单地通过参数传递的方式来共享数据。此外,传统方法调用中的try…catch…finally,using等关键字都无法跨越方法边界,因此异步编程在处理异常,保护资源等方面也需要花更大的精力才行。如果一不小心,轻则造成资源泄露,重则使整个应用程序崩溃。 因此,无论是微软官方还是社区中都出现了一些简化异步编程方式的组件,例如微软并行与协调运行时和Wintellect's .NET Power Threading Library中的AsyncEnumerator。同时,我基于AsyncEnumerator构建了一个AsyncTaskDispatcher组件,使多个有依赖关系的异步操作之间的协作调用得以大大简化。 以上是引用,自己做了个更简单的demo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值