Spring Boot实现@RequestScope请求域Bean时过滤器抛出空指针问题
问题根因
你用@RequestScope + CGLIB代理实现请求域共享Bean的整体思路是完全正确的,空指针的触发原因是自定义Filter的执行时机早于Spring请求上下文的初始化节点:
- 加了
@Component的Filter会被Servlet容器直接注册,执行优先级远早于Spring用于初始化请求上下文的RequestContextFilter - 此时请求域代理对象内部还没有绑定当前请求的实际实例,调用
setAppInfo方法时会因访问空实例触发NPE。
你代码中还存在几处拼写/语法错误,需同步修正:
- 类定义错误:
public Class RequestHeaderInfo应为public class RequestHeaderInfo - Servlet类名错误:
HTTPServletRequest应为HttpServletRequest - Controller注解错误:
@Contoller应为@Controller
可行解决方案
方案1:调整Filter的注册逻辑,对齐执行时机
- 移除
RequestFilter上的@Component注解,避免被Servlet容器默认自动注册 - 改用
FilterRegistrationBean手动注册Filter,设置执行顺序晚于Spring请求上下文初始化节点,同时将Spring容器管理的请求域代理对象传入Filter,避免依赖注入失效
代码示例:
// 移除原有@Component注解 public class RequestFilter implements Filter { private final RequestHeaderInfo requestHeaderInfo; public RequestFilter(RequestHeaderInfo requestHeaderInfo) { this.requestHeaderInfo = requestHeaderInfo; } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; requestHeaderInfo.setAppInfo(request.getHeader("appInfo")); chain.doFilter(req, res); } }
对应配置类:
@Configuration public class WebConfig { @Bean public FilterRegistrationBean<RequestFilter> registerRequestFilter(RequestHeaderInfo requestHeaderInfo) { FilterRegistrationBean<RequestFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(new RequestFilter(requestHeaderInfo)); // 优先级设置为在Spring RequestContextFilter之后执行 registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); registration.addUrlPatterns("/*"); return registration; } }
方案2:更可靠的替代实现——用HandlerInterceptor做请求头解析
Filter属于Servlet容器层面组件,不直接对接Spring MVC生命周期,如果仅需处理MVC链路内的请求头,用拦截器实现的可靠性更高:此时请求上下文已完全初始化,请求域Bean可正常读写,无需手动调整Filter执行顺序。
- 实现
HandlerInterceptor接口,在preHandle方法中完成请求头解析与属性设置 - 实现
WebMvcConfigurer接口,将自定义拦截器注册到MVC链路中
注意:所有请求域Bean必须配置
proxyMode = ScopedProxyMode.TARGET_CLASS,否则会因请求域生命周期与单例Bean生命周期不匹配,出现注入异常。
内容的提问来源于stack exchange,提问作者Lolly
相关产品推荐
相关产品推荐

