1. 拦截器和过滤器的概念
1.1. 过滤器概念
- 过滤器
Filter
是JavaEE标准,在Servlet
的规范中定义的,是Servlet
容器支持的,是属于Servlet
容器的,依赖Servlet
容器; - 若用配置文件方式(servlet3.0以下版本)配置,
Filter
配置在web.xml
中,Interceptor
配置在Spring MVC的配置文件中。多个过滤器的执行顺序跟在web.xml
文件中定义的先后关系有关。多个拦截器它们之间的执行顺序跟在SpringMVC的配置文件中定义的先后顺序有关。 - 过滤器
Filter
是基于函数回调实现(容器初始化调用);拦截器是基于java的反射机制实现,属于面向切面编程(AOP)的一种运用。
1.2. 拦截器概念
- 拦截器是基于java的反射机制的,而过滤器是基于函数回调。
- 拦截器不依赖与
servlet
容器,过滤器依赖与servlet
容器。 - 拦截器只能对
action
请求起作用,而过滤器则可以对几乎所有的请求起作用。 - 拦截器可以访问
action
上下文、值栈里的对象,而过滤器不能访问。 - 拦截器依赖于Spring框架,所以只能对
Controller
请求进行拦截而对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理,而过滤器则可以对几乎所有的请求起作用。
2. 两者区别:
- 拦截器是基于java的反射机制的,而过滤器是基于函数回调。
- 拦截器不依赖与
servlet
容器,过滤器依赖与servlet
容器。 - 拦截器只能对
action
请求起作用,而过滤器则可以对几乎所有的请求起作用。 - 拦截器可以访问
action
上下文、值栈里的对象,而过滤器不能访问。 - 在
action
的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。 - 拦截器可以获取
IOC
容器中的各个bean
,而过滤器就不行,这点很重要,在拦截器里注入一个service
,可以调用业务逻辑。 - 拦截器
Interceptor
是Spring的组件之一,是属于Spring框架的,依赖于Spring框架,归Spring管理,配置在Spring的文件中,因此能使用Spring里的任何资源和对象,例如Service
对象、数据源、事务管理等(所有Spring容器管理的bean
),所以可以通过Spring的IOC注入方式注入即可,而Filter
不可以。 - 若用配置文件方式(servlet3.0以下版本)配置,Filter配置在web.xml中,Interceptor配置在Spring MVC的配置文件中。多个过滤器的执行顺序跟在web.xml文件中定义的先后关系有关。多个拦截器它们之间的执行顺序跟在SpringMVC的配置文件中定义的先后顺序有关。
- 过滤器Filter是基于函数回调实现;拦截器是基于java的反射机制实现,属于面向切面编程(AOP)的一种运用。
- 拦截器是Spring组件之一,所以可以访问
action
上下文、栈里的对象、Spring容器管理的bean,而过滤器不能访问。 - 在
action
上下文的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化是被调用一次。
3. 触发时机
3.1. 代码示例
3.1.1. MyFilter.java
过滤器写法,实现javax.servlet.Filter
接口
import javax.servlet.*;
import java.io.IOException;
/**
* @author five-five
* @createTime 2022/3/2 10:37
*/
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...");
chain.doFilter(request, response);
System.out.println("after...");
}
@Override
public void destroy() {
}
}
3.1.2. MyInterceptor.java
拦截器写法,实现org.springframework.web.servlet.HandlerInterceptor
接口,也可继承org.springframework.web.servlet.HandlerInterceptor
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author five-five
* @createTime 2022/3/2 10:38
*/
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("afterCompletion");
}
}
3.2. 说明
3.2.1. 过滤器说明
过滤器的触发时机是容器后,servlet之前,所以过滤器的doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
方法的入参是ServletRequest
,而不是httpservletrequest
。因为过滤器是在httpservlet
之前。
过滤器是在请求进入容器后,但请求进入servlet
之前进行预处理的。请求结束返回也是,是在servlet
处理完后,返回给前端之前。
chain.doFilter(request, response);
这个方法的调用作为分水岭。事实上调用Servlet
的doService()
方法(处理请求,写过Servlet
原生的就会知道)是在chain.doFilter(request, response);
这个方法中进行的。
3.2.2. 拦截器说明
a.preHandle()
这个方法是在过滤器的chain.doFilter(request, response)
方法的前一步执行,也就是在
System.out.println("before...");
chain.doFilter(request, response);
之间执行。
postHandle()
方法之后,在return ModelAndView
之前进行,可以操控Controller
的ModelAndView
内容。
afterCompletion()
方法是在过滤器返回给前端前一步执行,也就是在
chain.doFilter(request, response);
System.out.println("after...");
之间执行。
SpringMVC的机制是由同一个Servlet来分发请求给不同的Controller,其实这一步是在Servlet的
service()
方法中执行的。
3.2.3. 执行顺序
所以过滤器、拦截器、service()
方法,dispatch()
方法的执行顺序应该是这样的。
4. 总结
- 灵活性上说拦截器
Interceptor
功能更强大些,Filter
能做的事情,Interceptor
都能做,而且可以在请求前,请求后执行,异常抛出时,比较灵活。 Filter
主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验(比较泛的,比如登录不登录之类),太细的话,还是建议用interceptor
。