拦截

Java / 2021-02-18

拦截器和过滤器执行顺序:

init -> doFilter -> servlet -> preInterceptor -> controller -> postInterceptor -> destroy

区别:

  • 过滤器基于函数回调实现,拦截器基于java反射机制(动态代理)
  • filter依赖于servlet,需要容器,比如Tomcat,只能使用在web中,interceptor是spring一个组件,spring容器管理,使用spring的地方就可以使用interceptor
  • 执行顺序,filter使用@Order规定顺序,intercetpor根据注册顺序
  • 拦截器要使用IOC容器中的东西需要在配置加入拦截器之前手动@Bean注入拦截器

Filter

容器启动时执行init方法

容器摧毁时执行destroy方法

对于每个请求执行doFilter方法

可以有多个过滤器,request和response交给filterChain传递给下一个filter

使用@Order定义过滤器执行顺序

filter接口的一个实现为OncePerRequestFilter,每个请求执行一次过滤

HandlerInterceptor

controller之前执行preHandle

controller之后执行postHandle

afterCompletion在整个请求结束之后, DispatcherServlet 渲染了对应的视图之后执行

每个方法如果返回false表示终止这个请求,流程到此结束

拦截器需要注册到IOC容器中,WebMvcConfigurer接口的实现中加入

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
}

AOP

@Aspect
@Component
public class LogAspect {

    @Pointcut("execution(* cn.redarm.springboottest.controller.*.*(..))")
    public void doPointcut(){}

    @Before("doPointcut()")
    public void recordLog(JoinPoint joinPoint){
        System.out.println("joinPoint.getArgs() = " + joinPoint.getArgs());
        System.out.println("joinPoint.getSignature().getName() = " + joinPoint.getSignature().getName());
    }
}

自定义注解拦截

注解:

@Inherited
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLogAnnotation {

    String logContent() default "默认value";
}

拦截器:

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    if (handler instanceof HandlerMethod) {
        Method method = ((HandlerMethod) handler).getMethod();
        // 如果方法带有MyLogAnnotation注解
        if (AnnotatedElementUtils.isAnnotated(method, MyLogAnnotation.class)) {
            MyLogAnnotation myAnnotation = method.getAnnotation(MyLogAnnotation.class);
            if (myAnnotation == null) {
                return true;
            }
            //获取注解的参数
            String logContent = myAnnotation.logContent();
            System.out.println("logContent = " + logContent);
            return true;
        }
    }
    return true;
}

注册拦截器:

registry.addInterceptor(new MyLogAnnotationInterceptor()).addPathPatterns("/**");