6

在我们的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()方法,它都应该返回相同的值(第一个请求的)。

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

  1. request.hashCode()in 控制器总是不同的(如我所料)
  2. request.hashCode()inRequestService总是一样的(就像我想的那样)
  3. 但是,如果我发出带有不同标头的请求,标头值会有所不同abc!!!

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

怎么理解?

4

1 回答 1

9

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

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

于 2015-01-19T07:59:38.940 回答