基于spring的三种拦截机制

首先说一下为什么引出这三种拦截机制

在某些应用场景下,对于一个用户而言,我们需要在他访问接口的时候去进行一系列的校验(身份、权限、系统关系等),同时也为了防止恶意攻击,出于系统内部的安全性考虑,有必要去进行加入拦截机制

三种拦截机制:包括最原始的filter、interceptor、aspect

一、Filter

创建filter类来实现Filter(servlet包下)类,实现init、doFilter和destory方法,在doFilter方法中去拦截请求,要想使Filter起作用:可以在过滤器类上添加注解@Component去拦截所有的请求,还可以通过配置去给特定的url去起作用,如下:

15200008-c6f82238cd0bae0d.png
过滤器配置

但是使用Fiter并不能知道哪个请求是用哪个过滤器的什么方法去处理的,因为所有的请求都是基于spring的。

二、interceptor

是Spring框架本身提供的。拦截器会拦截所有控制器

@Component
public class TimeInterceptor implements HandlerInterceptor {
    /**
     * 在控制器的方法调用之前调用
     * @param request
     * @param response
     * @param handler   比filter多的一个参数,真正用来处理逻辑的一个参数
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        //打印类名和方法名
        System.out.println(((HandlerMethod)handler).getBean().getClass().getName());
        System.out.println(((HandlerMethod)handler).getMethod().getName());
        request.setAttribute("startTime",new Date().getTime());

        return true;
    }

    /**
     * 在控制器的方法调用之后调用,但是抛出异常之后不会进入这个方法
     * @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("postHandle");
        Long start = (Long) request.getAttribute("startTime");
//        request.setAttribute("endTime",new Date().getTime()-);
        System.out.println("postHandle请求耗时:"+ (new Date().getTime() - start));
    }

    /**
     * 不管是正常调用还是抛出异常都会被调用
     * @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("afterCompletion");
        Long start = (Long) request.getAttribute("startTime");
//        request.setAttribute("endTime",new Date().getTime()-);
        System.out.println("afterCompletion请求耗时:"+ (new Date().getTime() - start));
        System.out.println("ex is " + ex);
    }
}

写完之后并不会生效,还需要去对其进行注册,注册的代码:

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private TimeInterceptor timeInterceptor;

    //拦截器的注册器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(timeInterceptor);
    }
}

这样,拦截器就会拦截所有的请求。
注意:在拦截器中,handler是用来过滤的方法,但是这个方法只能获取到此次请求所用到的那个类和那个方法,并不能看到传递的参数以及传递的对象。追踪源码:在DispatcherServlet中的doService方法里面调用了doDispatcher()方法,在doDispatcher()方法中有一个appplyPreHandle方法,这个方法就是去调用我们写的那个拦截器的preHandle方法,只有在preHandle方法返回true的时候才往下执行,下面会调用handle方法,在这个方法中会对请求中传递的参数进行拼装,将传递的JSON字符串等数据组装成我们需要的一些自定义对象。所以,采用拦截器的方法虽然能知道此次请求调用的类和方法,但是并不能知道请求中传递的参数,如果需要知道传递的参数,则需要使用切片(Aspect)的方式。

三、Aspect

这种方式主要使用了Spring的AOP的思想


15200008-19b0a0b2319c98ce.png
AOP思想
1.切入点

四个注解用来控制什么时候起作用:

  • @before 调用方法之前
  • @after 调用方法之后
  • @afterThrowing 调用方法之后,如果指定的方法抛出异常,则执行这个
  • @around 完全覆盖了之前的三种,都可以用这种方式
2.Aspect实现
15200008-2232b3aecb6d83ed.png
AspectJ实现

其中,注解中的表达式可以参考面向切面编程表达式的写法
我们推荐使用这个去进行拦截,但是缺点是拿不到原始的http请求和响应的那两个对象

四、拦截顺序

15200008-c0ed356a779e1002.png
三种拦截机制的拦截顺序
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值