过滤器、拦截器、切面之间的比较

本文对比分析了过滤器(Filter)、拦截器(Interceptor)与切面(AOP)三种技术的实现原理、使用场景及具体应用方式,并总结了它们在执行过程中的特点与区别。

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

过滤器、拦截器、切面之间的比较

一、过滤器(Filter)

  1. 实现原理
  • 过滤器是基于函数回调来实现
  1. 使用场景
  • 过滤url级别权限、过滤敏感词、设置字符编码等
  1. 具体使用
  • 实现javax.servlet.Filter接口,重写init()、doFilter()、destroy()方法
  • 具体解释在代码注释中
/**
 * @author lqh
 * @date 2020/12/3
 */
@Component
@WebFilter(urlPatterns = "/**" , filterName = "MyFilter" )//可通过xml配置或@WebFilter实现对特定URL拦截
public class MyFilter implements Filter{
    /**
     * init():此方法在容器初始化时被调用,在Filter生命周期中只会被调用一次。注意:此方法必须执行成功,否则过滤器不起作用
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter-init...");
    }

    /**
     * 每次请求都会调用该方法,FilterChain用来调用下一个过滤器
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Filter-doFilter...");
 /*        System.out.println(((HttpServletRequest) servletRequest).getRequestURI());
           System.out.println(((HttpServletRequest) servletRequest).getRequestURL());*/
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("Filter-doFilter后...");
    }

    /**
     * 容器销毁过滤器调用该方法,整个生命周期只会被调用一次
     */
    @Override
    public void destroy() {
        System.out.println("Filter-destroy...");
    }
}

二、拦截器(Interceptor)

  1. 实现原理
  • 拦截器是基于反射(动态代理)来实现
  1. 使用场景
  • 权限认证(比如拦截未登录的用户)、审计日志等
  1. 具体使用
  • 实现HandlerInterceptor接口,重写preHandle、postHandle、afterCompletion方法
/**
 * 拦截器:是链式调用,一个应用中可以同时存在多个拦截器,一个请求可以触发多个拦截器,拦截器的执行顺序和它的声明顺序有关
 * 实现HandlerInterceptor接口,请求的拦截通过此接口实现
 * 需要注意的是,拦截器是基于Spring的,且只有通过DispatcherServlet的请求才能被拦截
 */

public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("Interceptor-preHandle...");
        return true;
        //return false;如果返回false,将视为请求结束,不仅自身拦截器失效(postHandle\afterCompletion都不会执行),还会导致其他拦截器失效
    }

    /**
     * Controller方法调用之后,DispatcherServlet返回视图之前被调用
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Interceptor-postHandle...");
    }

    /**
     * DispatcherServlet图渲染结束之后被调用
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("Interceptor-afterCompletion...");
    }
}
  • 注册拦截器
/**
 * @author lqh
 * @date 2020/12/3
 * 注册拦截器
 */
@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {
    /**
     * addPathPatterns需要拦截的请求;excludePathPatterns需要排除的请求
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/post","/favicon.ico");
    }
}

三、切面(@Aspect、@ControllerAdvice)

  1. 实现原理
  • 切面基于动态代理实现
  1. 使用场景
  • 日志记录,性能统计,安全控制,事务处理,异常处理
  1. 具体使用
  • @Aspect 配置切入点、前置通知、后置通知
@Aspect
@Component
public class MyAspect {

    @Pointcut("execution(* cn.openwit.springbootnotebook.controller.*Controller.*(..))")
    public void declareJointPointExpression() {
    }
    @Before("declareJointPointExpression()")
    public void beforeMethod(){
        System.out.println("Aspect-Before....");
    }
    @After("declareJointPointExpression()")
    public void afterMethod(JoinPoint joinPoint) {
        System.out.println("Aspect-After....");
    }
}
  • @ControllerAdvice全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 全局处理异常
     * @param e
     */
    @ExceptionHandler(value = Exception.class)
    public void serviceExceptionHandle(Exception e){
        System.out.println("ControllerAdvice...");
    }
}

四、执行结果验证

  • http请求接口
@Controller
public class IndexController {

    @GetMapping("/index")
    public String index(){
        System.out.println("Controller中index-return前...");
        if(true){
            //throw new RuntimeException();
            return "index";
        }
        System.out.println("Controller中index-return后...");
        return "index";
    }
}
  1. 无异常结果

在这里插入图片描述
2. #### 无异常结果
在这里插入图片描述
由以上结果我们可以看出

  • 过滤器:可以拿到原始http请求,却拿不到请求的控制器和请求控制器中的方法的信息
  • 拦截器:可以拿到请求的控制器和方法,却拿不到请求方法的参数
  • 切片:可以拿到方法的参数,却拿不到http请求和响应的对象

四、执行结果验证

借鉴两张图片进行说明
在这里插入图片描述
在这里插入图片描述

  • 过滤器
    • 使用范围
      在这里插入图片描述
        Filter接口时javax.servlet包中的,servlet规范中的,依赖与Tomcat等容器使用,只能在web应用中使用

    • 具体实现原理
      自定义中doFilter方法
      在这里插入图片描述
      FilterChain接口源码
      在这里插入图片描述
      FilterChain接口的具体实现类
      在这里插入图片描述
      在这里插入图片描述
      此处filter.doFilter()实现回调

  • 过滤器
    • 使用范围
      在这里插入图片描述
      拦截器说Spring的组件,由Spring容器进行管理,不依赖于tomcat容器,可以单独使用。

五、过滤器(Filter)与拦截器(Interceptor)区别:

  1、过滤器是基于函数回调,而拦截器是基于java的反射机制;

  2、过滤器是servlet规范规定的,只能用于web程序中,而拦截器是在spring容器中,它不依赖servlet容器

  3、过滤器可以拦截几乎所有的请求(包含对静态资源的请求),而拦截器只拦截action请求(不拦截静态资源请求)

  4、过滤器不能访问action上下文及值栈里的对象,而拦截器都是可以的。

  5、拦截器可以获取spring容器里的对象,而过滤器是不行的

  6、拦截器在action的生命周期内是可以多次调用,而过滤器只在容器初始化时被调用一次。

  7、拦截器是被包裹在过滤器之中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值