Spring Boot Interceptor 使用 @Autowired 注入为 null 的解决方法

in 编程 with 2 comments

最近使用 Spring Boot 的 Interceptor(拦截器),在拦截器中注入了一个 DAO,结果却得到 null

错误复现

原先报错的代码如下:

InterceptorConfiguration.java

@Configuration
public class InterceptorConfiguration implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(new UserLoginInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/register", "/login");

    }

}

UserLoginInterceptor.java

public class UserLoginInterceptor implements HandlerInterceptor {

    @Autowired
    private UserMapper userMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    }

}

错误原因

Interceptor 的加载在 Spring Context 创建完成之前,所以在拦截器中注入实体就为 null 了。

解决方法

解决方法有很多,这里主要提两种方法。

使用 @Bean 注解提前加载

根据官方描述,「You are free to use any of the standard Spring Framework techniques to define your beans and their injected dependencies.」,因此只需要将 Interceptor 注册为一个 Bean,就可以正常的使用 @Autowired 注解了:

InterceptorConfiguration.java

@Configuration
public class InterceptorConfiguration implements WebMvcConfigurer {

    @Bean
    public UserLoginInterceptor userLoginInterceptor() {
        return new UserLoginInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(userLoginInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/register", "/login");

    }

}

将 Interceptor 作为 Component 加载

上面的方法比较繁琐,不但要 new 一个对象,还得封装成一个方法,那么下面这种方法就显得比较优雅了:

UserLoginInterceptor.java

@Component
public class UserLoginInterceptor implements HandlerInterceptor {

    @Autowired
    private UserMapper userMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    }

}

InterceptorConfiguration.java

@Configuration
public class InterceptorConfiguration implements WebMvcConfigurer {

    @Autowired
    private UserLoginInterceptor userLoginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(userLoginInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/register", "/login");

    }

}
Responses
  1. 哈哈, 其实的问题就是你要把Interceptor交给spring管理

    Reply
    1. @乐心湖

      是的,第一次用拦截器 😂。之前不知道它在 Spring 上下文创建完成之前就加载完了,还得手动注入

      Reply