无法很好地理解 spring-mvc 的“@Autowired HttpServletRequest”

Can't understand `@Autowired HttpServletRequest` of spring-mvc well

在我们的 spring 应用程序中,我们以两种方式使用 HttpServletRequest

(这里的代码很简单,看起来没什么意义)

  1. 在控制器中:

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<String> hello(HttpServletRequest request) {
        System.out.println("## controller req.hashcode: " + request.hashCode());
        System.out.println("## header 'abc': " + request.getHeader("abc"));
        return new ResponseEntity<String>("OK", HttpStatus.OK);
    }
    
  2. 在普通组件中:

    @Component
    class RequestService {
        private final HttpServletRequest request;
        @Autowired
        public RequestService(HttpServletRequest request) {
            this.request = request;
        }
        public String getHeaderAbc() {
            System.out.println("## service req.hashcode: " + request.hashCode());
            return this.request.getHeader("abc");
        }
    }
    

起初,我认为第二种方式是完全错误的,因为它应该只注入一次 request 实例。所以无论我什么时候调用 getHeaderAbc() 方法,它都应该 return 相同的值(第一个请求的)。

但是当我尝试的时候,我发现了几个有趣的事情:

  1. controller 中的 request.hashCode() 总是不同的(如我所料)
  2. RequestService中的request.hashCode()总是一样的(和我想的一样)
  3. 但是如果我用不同的 header abc 发出请求,header 值是不同的!!!

对于单例 RequestService,spring 似乎保留了 request 实例,但更改了它包含的 headers!

如何理解?

看看作用域代理。 http://www.java-allandsundry.com/2012/08/spring-scoped-proxy.html 基本上,您注入一个代理,该代理保留对当前 HttpRequest bean 的引用,并为您提供正确的代理,通过请求 ID 选择它。

恕我直言,在 Web 层之外使用 HttpRequest 并不是一个好的做法。我只会在控制器中使用它。