filter过滤器和interceptor拦截器的区别和执行顺序

1.过滤器

      过滤器是一个程序,它先于与之相关的servlet或JSP页面运行在服务器上。它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的web应用停止或重新部署的时候才销毁。
作用
      请求和回应的过滤,传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者struts的action前统一设置字符集,或者去除掉一些非法字符(聊天室经常用到的,一些骂人的话)。

Servlet过滤器的基本原理
      在请求进入容器之后,还未进入Servlet之前进行预处理;在请求结束返回给前端之前进行后期处理。处理完成后,它会交给下一个过滤器处理,直到请求发送到目标为止。

2.拦截器

      拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。比如日志,安全等。
      拦截器链,就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
一般拦截器方法都是通过动态代理的方式实现。

作用
比如通过它来进行权限验证,或者判断用户是否登陆,或者是像12306 判断当前时间是否是购票时间。

3.区别

      ①拦截器是基于动态代理的,属于面向切面编程(AOP)的一种运用;而过滤器是基于函数回调。
  ②拦截器不依赖于servlet容器,通过动态代理实现;过滤器依赖于servlet容器。
  ③拦截器可以在方法前后,异常前后等多次调用,而过滤器只能在某一次请求前和请求后各调用一次。
      ④过滤器几乎可以过滤所有的请求,包括页面、图片、js等静态资源以及请求;而拦截器只能对一些action或者controller进行拦截。
  ⑤拦截器可以利用依赖注入,而过滤器则不能直接注入(
原因详情见:http://blog.csdn.net/qq_39470733)因此在Spring框架程序中,优先拦截器。

 

4.如果在一个项目中仅仅只有一个拦截器或者过滤器,那么我相信相对来说理解起来是比较容易的。但是我们是否思考过:如果一个项目中有多个拦截器或者过滤器,那么它们的执行顺序应该是什么样的?或者再复杂点,一个项目中既有多个拦截器,又有多个过滤器,这时它们的执行顺序又是什么样的呢?

(1)先定义两个过滤器:
①filter过滤器 1
public class TestFilter1 extends OncePerRequestFilter {  
  
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  
            throws ServletException, IOException {  
        //在DispatcherServlet之前执行  
        <a target="_blank" href="http://www.07net01.com/tags-system-0.html" class="infotextkey" style="background:transparent; color:rgb(66,139,202)">system</a>.out.println("############TestFilter1 doFilterInternal executed############");  
        filterChain.doFilter(request, response);  
        //在视图页面返回给<a target="_blank" href="http://www.07net01.com/tags-%E5%AE%A2%E6%88%B7%E7%AB%AF-0.html" class="infotextkey" style="background:transparent; color:rgb(66,139,202)">客户端</a>之前执行,但是执行顺序在Interceptor之后  
        System.out.println("############TestFilter1 doFilter after############");  
    }
} 

②filter过滤器 2

public class TestFilter2 extends OncePerRequestFilter {  
  
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  
            throws ServletException, IOException {  
        System.out.println("############TestFilter2 doFilterInternal executed############");  
        filterChain.doFilter(request, response);  
        System.out.println("############TestFilter2 doFilter after############");  
    }    
} 

在web.xml中注册这两个过滤器

    <!-- 自定义过滤器:testFilter1 -->   

   <filter>  
        <filter-name>testFilter1</filter-name>  
        <filter-class>cn.zifangsky.filter.TestFilter1</filter-class>  
    </filter>  
    <filter-mapping>  
        <filter-name>testFilter1</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>  
    <!-- 自定义过滤器:testFilter2 -->   
   <filter>  
        <filter-name>testFilter2</filter-name>  
        <filter-class>cn.zifangsky.filter.TestFilter2</filter-class>  
    </filter>  
    <filter-mapping>  
        <filter-name>testFilter2</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>

(2)再定义两个拦截器:

①拦截器 1 

public class BaseInterceptor implements HandlerInterceptor{      
    /** 
     * 在DispatcherServlet之前执行 
     * */  
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {  
        System.out.println("************BaseInterceptor preHandle executed**********");  
        return true;  
    }  

    /** 
     * 在controller执行之后的DispatcherServlet之后执行 
     * */  
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)  
            throws Exception {  
        System.out.println("************BaseInterceptor postHandle executed**********");  
    }  
      
    /** 
     * 在页面渲染完成返回给客户端之前执行 
     * */  
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)  
            throws Exception {  
        System.out.println("************BaseInterceptor afterCompletion executed**********");  
//      Thread.sleep(10000);  
    }  
}

②拦截器 2

public class TestInterceptor implements HandlerInterceptor {  
  
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {  
        System.out.println("************TestInterceptor preHandle executed**********");  
        return true;  
    }  
  
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)  
            throws Exception {  
        System.out.println("************TestInterceptor postHandle executed**********");  
    }  
  
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)  
            throws Exception {  
        System.out.println("************TestInterceptor afterCompletion executed**********");  
    }  
}  

③在SpringMVC配置文件中配置拦截器

<!-- 拦截器 -->  
nbsp;   <mvc:interceptors>  
    <!-- 对所有请求都拦截,公共拦截器可以有多个 -->  
    <bean name="baseInterceptor" class="cn.zifangsky.interceptor.BaseInterceptor" />  
    <!-- <bean name="testInterceptor" class="cn.zifangsky.interceptor.TestInterceptor" /> -->  
    <mvc:interceptor>       
        <!-- 对/test.html进行拦截 -->  
        <mvc:mapping path="/test.html"/>  
        <!-- 特定请求的拦截器只能有一个 -->  
        <bean class="cn.zifangsky.interceptor.TestInterceptor" />  
    </mvc:interceptor>  
</mvc:interceptors>  

(3)定义一个测试controller:

@Controller  
public class TestController {  
      
    @RequestMapping("/test.html")  
    public ModelAndView handleRequest(){  
        System.out.println("---------TestController executed--------");  
        return new ModelAndView("test");  
    }  
} 

 

(4)定义一个测试页面:

<body>  
    <%  
        System.out.println("test.jsp is loading");  
    %>  
    <div align="center">  
        This is test page  
    </div>  
</body> 

(5)测试效果:

①单独访问filter的测试请求  http://localhost:8080/FilterDemo

 

这就说明过滤器的运行是依赖于servlet容器的,跟springmvc等框架并没有关系。并且,多个过滤器的执行顺序跟xml文件中定义的先后关系有关

②接着清空控制台中的输出内容并访问:http://localhost:8080/FilterDemo/test.html

相信从这个打印输出,大家就可以很清晰地看到有多个拦截器和过滤器存在时的整个执行顺序了。当然,对于过个拦截器它们之间的执行顺序跟在SpringMVC的配置文件中定义的先后顺序有关

如有披露或问题欢迎留言或者入群探讨

### Java中拦截器过滤器执行顺序及其区别 在Java Web开发中,**过滤器Filter)** **拦截器Interceptor)** 是两个重要的概念,它们都用于拦截HTTP请求并对请求或响应进行预处理或后处理。然而,两者的运行机制、配置方式以及执行顺序存在显著差异。 #### 1. 过滤器拦截器的主要区别 - **运行环境** - 过滤器是由Servlet容器管理的标准组件,适用于任何基于Servlet的应用程序[^3]。 - 拦截器则由Spring框架提供支持,主要用于Spring MVC生态系统内的请求处理。 - **配置方式** - 过滤器通常通过`web.xml`文件或使用`@WebFilter`注解来声明[^3]。 - 拦截器需要在Spring的配置类中显式注册,例如通过实现`WebMvcConfigurer`接口并调用`addInterceptors()`方法[^3]。 - **功能范围** - 过滤器仅能操作`HttpServletRequest``HttpServletResponse`对象。 - 拦截器不仅可以操作这些标准对象,还可以访问Spring MVC特有的组件,如`Handler`实例`ModelAndView`对象。 #### 2. 执行顺序分析 根据已有资料[^2],过滤器拦截器执行顺序遵循以下规律: - 当一个HTTP请求到达服务器时,首先会经过过滤器链中的各个过滤器。 - 接着,在进入目标控制器之前,拦截器的`preHandle()`方法会被调用。 - 响应生成之后,拦截器的`postHandle()`方法会在视图渲染完成前被调用。 - 最终,在整个请求结束且响应发送回客户端之前,拦截器的`afterCompletion()`方法被执行,随后控制权交还给过滤器链以完成后续清理工作。 具体来说,典型的执行流程如下: 1. Filter Chain -> doFilter() 2. Interceptor -> preHandle() 3. Controller Logic Execution 4. Interceptor -> postHandle() 5. View Rendering (if applicable) 6. Interceptor -> afterCompletion() 7. Final Response Sent Back to Client via Filters[^2] #### 3. 示例代码展示 ##### (1)过滤器示例 ```java import javax.servlet.*; import java.io.IOException; @WebFilter(filterName = "myFilter", urlPatterns = {"/*"}) public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("Before filtering..."); chain.doFilter(request, response); System.out.println("After filtering..."); } @Override public void destroy() {} } ``` ##### (2)拦截器示例 ```java import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("Pre-handle method called"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("Post-handle method called"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("After-completion method called"); } } ``` ##### (3)测试结果说明 假设我们有这样一个简单的API端点: ```java @RestController @RequestMapping("/example") public class ExampleController { @GetMapping("/hello") public String sayHello() { return "Hello from controller!"; } } ``` 当发出GET请求至`/example/hello`时,终端输出可能类似于这样: ``` Before filtering... Pre-handle method called [Controller logic executed here] Post-handle method called After-completion method called After filtering... ``` 这表明了各部分按照预期顺序依次触发。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值