【问题标题】:Scope of a Spring-Controller and its instance-variablesSpring-Controller 及其实例变量的范围
【发布时间】:2012-06-23 18:30:20
【问题描述】:

Spring-MVC 中的所有控制器都是单例的,并且在不同的会话和请求之间共享吗?

如果是这样,我假设类变量像

public String name;

所有请求和会话都相同吗?所以如果用户 X 发出请求并且 name 被设置为 Paul,那么用户 Z 也有 Paul 作为属性?

在我的情况下,我不希望这种行为,但想知道是否有比 session.getAttribute()/request.getAttribute() 更简单或更清晰的 OOP 方式来拥有会话/请求变量

【问题讨论】:

    标签: spring spring-mvc


    【解决方案1】:

    是的,Spring-MVC 中的控制器是单例的。在多个请求之间,您的类变量会被共享,并可能导致歧义。 您可以在控制器上方使用 @Scope("request") 注释来避免这种歧义。

    【讨论】:

    • 一些带有解释的例子会很棒。
    • @Controller public class TestClass { private String name; @RequestMapping("/") public String displayName(){ if(this.name != null){ this.name = "ABC"; }else{ this.name = "XYZ"; } SystemOut.println(name);返回这个名称; } public String getName() { 返回名称; } public void setName(String name) { this.name = name; } }
    • 继续我之前的编辑。对于第一个请求,它将打印 XYZ,但对于另一个并行请求,它将打印 ABC,但理想情况下,如果两个用户发出两个不同的请求,他们都应该看到 XYZ。通过制作 @Scope("request") 会给我们想要的结果。如果我在某个地方出错了,请告诉我
    • 是的,效果很好。 @Scope("request") 注释实际上做了什么?这会为每个请求创建一个新的控制器对象吗?如果两个请求同时到达同一个 requestMapping 怎么办?
    • @New Bee,是的,它会为每个 http 请求创建新实例,如果同时出现 2 个请求,那么它将创建单独的实例并处理请求。
    【解决方案2】:

    回答你的第一个问题:是的,Spring MVC 控制器默认是单例的。对象字段将永远对所有请求和所有会话共享和可见。

    但是,如果没有任何同步,您可能会遇到各种并发问题(竞争条件、可见性)。因此,您的字段应该有 volatile(顺便说一下,private)修饰符以避免可见性问题。

    回到您的主要问题:在 Spring 中,您可以使用 request-(参见 4.5.4.2 Request scope)和 session-scoped(参见:4.5.4.3 Session scope)bean。您可以将它们注入控制器和任何其他 bean(甚至是单例!),但 Spring 确保每个请求/会话都有一个独立的实例。

    在将请求和会话范围的 bean 注入单例时,唯一要记住的是将它们包装在范围代理中(示例取自 4.5.4.5 Scoped beans as dependencies):

    <!-- an HTTP Session-scoped bean exposed as a proxy -->
    <bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
    
        <!-- instructs the container to proxy the surrounding bean -->
        <aop:scoped-proxy/>
    </bean>
    

    【讨论】:

    • +1 注意:“即使是单身人士!”需要自动代理注入的 bean
    • @SeanPatrickFloyd:是的,这很重要,我从 Spring 文档中添加了一个示例,谢谢!
    • stackoverflow.com/questions/4503606/…,使用@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) 使用注解配置aop:scoped-proxy。
    • 我们缺少 spring 的基础之一:控制器是 bean,因此它们不应该有状态(除了注入的依赖项),除非这些 bean 是用来存储数据的。为了避免请求之间的数据共享,我在 jsf 中看到了支持表单的 @scope 会话或请求(正确配置为使用 spring bean)。控制器不是用来承载数据的 bean,而是支持视图逻辑的类,因此它们应该是无状态的,因此应该是单例的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 2014-08-12
    • 2014-04-18
    • 2015-11-15
    • 2011-08-09
    • 2017-11-08
    相关资源
    最近更新 更多