在Spring MVC中,Controller是单例,为什么我的代码是线程安全的?(Autowired HttpServeltRequest)

时间:2017-01-30 10:19:19

标签: java spring multithreading spring-mvc servlets

这对我来说很奇怪。 我有以下代码:

@Controller
public class MyTestController {
    @Autowired
    private HttpServletRequest request;

    @RequestMapping("/print/")
    public String PrintInfo() throws Exception {

        Thread.sleep(5000);
        System.out.println("name:" +request.getParameter("name"));
        System.out.println("hashcode:" +request.hashCode());

        return "testpage";
    }
}

我同时访问了以下网址:

http://127.0.0.1:8080/MyApp/print/?name=tom
http://127.0.0.1:8080/MyApp/print/?name=mike

打印出来:

 name:tom
 hashcode:2006506443
 name:mike
 hashcode:2006506443

MyTestContorller是单身人士。请求的哈希码是相同的,这意味着不同的请求具有相同的实例。

但为什么request.getParameter("name")能给我正确的结果呢? 也许getParameter方法只是一个需要从其他对象读取数据的方法?

我不知道,这让我很困惑。任何人都可以解释一下吗?

2 个答案:

答案 0 :(得分:2)

摘录from the official documentation应该回答您的问题:

  

作为依赖项的作用域

     

Spring IoC容器不仅管理你的实例化   对象(bean),也是协作者的联络(或   依赖)。如果您想注入(例如)HTTP请求   您可以选择将scoped bean 放入另一个更长寿的范围的bean中   注入AOP代理来代替scoped bean。也就是说,你需要   注入一个公开与公共接口相同的公共接口的代理对象   范围内的对象,但也可以从中检索真实的目标对象   相关范围(例如HTTP请求)和委托方法调用   在真实物体上。

请求范围基于RequestContextHolder中的线程局部属性(默认情况下,DispatcherServlet为每个请求初始化)。

所以你的HttpServletRequest是一个动态JDK代理,它在每次方法调用时检查线程局部属性以获取真实的请求对象并调用它。

可解析请求依赖项本身作为WebApplicationContext初始化WebApplicationContextUtils的一部分注册为bean。

这是一个简化的图表(图片中的所有内容实际上都是单例):

request scope flow

答案 1 :(得分:0)

我说你的 MyTestController 是单身,但实现 HttpServletRequest 的类不是。

每次收到请求时,底层服务器中的servlet容器都会为该类创建一个新实例,该实例为 HttpServletRequest 接口提供实现,然后该对象的引用将传递给 MyTestController

这就像每次调用时将不同的参数传递给方法一样。