Spring Boot Interceptor 使用 @Autowired 注入为 null

Spring Boot Interceptor 使用 @Autowired 注入为 null

Published date
Feb 13, 2020
Tags
Java
Spring Boot
Description
通过 debug 了解 Spring Boot 生命周期
最近使用 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"); } }