【问题标题】:In Spring MVC, Controller is singleton,why my code is thread safe?(Autowired HttpServeltRequest)在 Spring MVC 中,Controller 是单例的,为什么我的代码是线程安全的?(Autowired HttpServeltRequest)
【发布时间】:2017-01-30 10:19:19
【问题描述】:

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

@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 是单例的。请求的hashcode相同,表示不同的请求具有相同的实例。

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

我不知道,这让我很困惑。谁能解释一下?

【问题讨论】:

  • 打印您的请求的类...它可能是一个 JDK 代理,它能够从正确的范围中提取依赖项(由RequestContextHolder 上的本地线程保留)。我认为 Spring 文档中有一章专门讨论这个......
  • 魔法。我说这是一种邪恶的魔法:)这个聪明的把戏破坏了我们对物体的常识。

标签: java spring multithreading spring-mvc servlets


【解决方案1】:

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

作用域 bean 作为依赖项

Spring IoC 容器不仅管理您的实例化 对象(bean),还有协作者(或 依赖项)。如果您想注入(例如)一个 HTTP 请求 scoped bean 转换成 longer-lived scope 的另一个 bean,你可以选择 注入一个 AOP 代理来代替作用域 bean。也就是说,你需要 注入一个代理对象,该对象公开与 范围对象,但也可以从中检索真正的目标对象 相关范围(例如 HTTP 请求)和委托方法调用 到实物上。

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

所以您的HttpServletRequest 是一个动态JDK 代理,它在每次方法调用时都会检查线程本地属性以获取真正的请求对象并调用它。

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

还有一点简化图(图中的一切其实都是单例):

【讨论】:

  • 谢谢。根据您的回答,它需要一些配置。但我没有配置任何 AOP 代理。那么这些神奇的事情是如何发生的呢?
  • 不...这是开箱即用的东西。 Spring 为默认场景做了很多自动配置。我只是在彻底解释“幕后”发生的事情:)。 您可以通过放置断点 + 检查堆栈跟踪来验证这一点(请这样做 - 这是了解任何框架内部运作的最佳方式)。
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多