解决SpringBoot项目Interceptor中Redis注入异常

问题描述

修改博客系统后台,发现了在SpringBoot项目添加Interceptor拦截器时,Redis注入存在报空指针异常

Interceptor 简介

  • Interceptor是什么

拦截器(Interceptor)同 Filter 过滤器一样,它俩都是面向切面编程——AOP 的具体实现(AOP切面编程只是一种编程思想而已)。

  • Interceptor用途

    • 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等
    • 权限检查:如登录检测,进入处理器检测是否登录
    • 性能监控:通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间。(反向代理,如 Apache 也可以自动记录)
    • 通用行为:读取 Cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的即可使用拦截器实现。
  • Interceptor用法
    要使用Interceptor的话,需要先实现springboot提供的 HandlerInterceptor类 :

public class MyInterceptor implements HandlerInterceptor {

}
java

其中HandlerInterceptor这个类源码:

public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}
java

里面有这三个接口

  • preHandle:这个是请求来的时候,访问controller之前,会先调用这里,可以在这里获取请求数据,请求方式等等,当这个方法返回false时表示请求结束、返回true则会继续调用下去

  • postHandle:在当前请求处理完成之后,也就是 Controller 方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用

  • afterCompletion:方法需要在当前对应的 Interceptor 类的 preHandle 方法返回值为 true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行。此方法主要用来进行资源清理。

例如我们实现preHandle:

public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            String name = method.getName();
            System.out.println(name);
            if (name.equals("getUserList")) {
                 return false;
            }
        }
        return true;
    }
}

java

上面做了对请求方法名getUserList的拦截

根据所需实现完之后,还需要在MVCConfig里面添加自定义的Interceptor:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //api请求过滤
        registry.addInterceptor(new MyInterceptor());
    }
}
java

就可以实现拦截功能了

Interceptor使用Redis

使用Redis场景

想对请求进行拦截,防止频繁提交,考虑用Redis做请求缓存,检查是否已经请求过了

遇到问题

在把redis进行注入的时候,发现redis没有被初始化,一直是null

public class MyInterceptor  implements HandlerInterceptor {

    @Autowired
    private RedisService redisService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            String name = method.getName();
            System.out.println(name);
            if (name.equals("getUserList")) {
                 return false;
            }
        }
        return true;
    }
}

java

问题原因

查阅资料发现,拦截器在SpringContext初始化之前就执行了,Bean初始化之前它就执行了,所以它肯定是无法获取SpringIOC容器中的内容的。

解决方法

让拦截器执行的时候实例化拦截器Bean,在拦截器配置类里面先实例化拦截器,然后再获取就能解决这个问题啦

  • 方法一:使用注解@Autowired
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //api请求过滤
        registry.addInterceptor(myInterceptor);
    }
}
java
  • 方法二:使用注解@Bean
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Bean
    public MyInterceptor  getMyInterceptor(){
        return new MyInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //api请求过滤
        registry.addInterceptor(getMyInterceptor());
    }
}
java
打赏
  • 微信
  • 支付宝
评论
来发评论吧~
···

歌手: