使用@Autowire注入HttpServletRequest出现空指针异常的原因排查
问题:为何
HttpServletRequest注入后为Null? 编写了如下Spring代码:
package com.example.helloworld; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.annotation.RequestScope; @RestController public class HelloWorldController { @GetMapping("/") public ResponseEntity<String> getGet( @Autowired Foo foo) { foo.sayHi(); return new ResponseEntity<>("OK", HttpStatus.OK); } } @Component @RequestScope class Foo { private @Autowired HttpServletRequest request; public void sayHi() { var name = this.request.getHeader("x-user-name"); System.out.println("Hi " + name); } }
执行curl命令 curl -H x-user-name:capybara http://localhost:8080 时,出现如下错误:
2022-09-09 17:07:28.623 ERROR 26350 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException: Cannot invoke "javax.servlet.http.HttpServletRequest.getHeader(String)" because "this.request" is null] with root cause java.lang.NullPointerException: Cannot invoke "javax.servlet.http.HttpServletRequest.getHeader(String)" because "this.request" is null at com.example.helloworld.Foo.sayHi(HelloWorldController.java:32) ~[classes!/:0.0.1-SNAPSHOT] at com.example.helloworld.HelloWorldController.getGet(HelloWorldController.java:19) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:577) ~[na:na] at ...
参考相关解答后仍未解决,为何this.request会为null?
原因分析
核心问题是在控制器方法参数上直接使用@Autowired注入请求作用域的Bean,这绕过了Spring对请求作用域Bean的代理机制:
Foo是@RequestScope的Bean,正常情况下Spring会为其创建代理对象,只有在请求上下文完全初始化后,才会实例化真实的Foo对象并注入HttpServletRequest。- 但在方法参数上标注
@Autowired,Spring会在方法调用前提前尝试获取Foo的实例,此时请求上下文尚未准备完成,导致真实Foo对象创建时,HttpServletRequest无法被正常注入,最终出现NullPointerException。
解决方法
方法1:将Foo作为控制器成员变量注入
@RestController public class HelloWorldController { @Autowired private Foo foo; @GetMapping("/") public ResponseEntity<String> getGet() { foo.sayHi(); return new ResponseEntity<>("OK", HttpStatus.OK); } }
方法2:移除方法参数上的@Autowired
Spring会自动解析方法参数中的Spring管理Bean,无需额外标注@Autowired,此时能正确处理请求作用域代理:
@GetMapping("/") public ResponseEntity<String> getGet(Foo foo) { foo.sayHi(); return new ResponseEntity<>("OK", HttpStatus.OK); }
方法3:通过RequestContextHolder获取请求
绕过依赖注入,直接从请求上下文获取HttpServletRequest:
@Component @RequestScope class Foo { public void sayHi() { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); var name = request.getHeader("x-user-name"); System.out.println("Hi " + name); } }
内容的提问来源于stack exchange,提问作者Renato
相关产品推荐
相关产品推荐

