【问题标题】:Spring Singleton behavior in a multi-threaded environment多线程环境中的 Spring Singleton 行为
【发布时间】:2021-03-03 03:31:12
【问题描述】:

我是春天的新手。在阅读documentation 时,我发现它提到了这一点

Bean 默认作用域是单例。

如果容器中只有一个实例,那么“它在多线程环境中的行为方式”。

通常在任何 Web 应用程序中,多个请求将同时完成,如果一个 POJO 类是自动装配的并且多个请求同时完成,那么 getter 和 setter 将相互交叉数据。请求 1 设置数据,同时请求 2 覆盖。请求 1 获取请求 2 的覆盖数据。

Like Foo 是一个 POJO 类,它的 get 和 set 不同步。

 @Service
    public class Foo {
        String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

   

     @Autowired
        private Foo foo;
    
        @RequestMapping(value = "foo" , method = RequestMethod.POST )
        public String saveFoo(@RequestBody String fooname){
            foo.setName(fooname);  // In case of multiple request 
                                  //get and set will be happing on same instance could be wrong
            return foo.getName();
        }

在多线程环境中处理 Autowire 和 POJO 的理想方式是什么?开发者是否必须提及原型范围?

【问题讨论】:

  • Spring bean 不是线程安全的.......提供线程安全是您的责任。
  • yu 使用 spring 并不意味着 一切 都必须由 Spring 管理。为此,在您需要时创建一个Foo,它是完全线程安全的。您当前的代码不是将状态保持在单例中。

标签: java spring


【解决方案1】:

一般来说,服务对象应该是无状态的。您的问题是您将数据直接存储在您的Foo 中,这不是它所属的位置。对服务的调用应该在方法签名中包含所有必要的参数;持久对象应该保存在某个地方(如数据库)并通过键引用(可能保存在 HTTP 会话中或作为请求参数发送)。

【讨论】:

  • 我们如何自动装配 pojo 类?想象一下需要形成基于请求体数据pojo的场景。你是说在保存到实体之前我们不应该有自动装配的 pojo 类吗?能否请您添加一些示例代码
  • @Sumeet 不要自动装配 POJO。自动装配适用于服务,您应该明确区分服务数据对象
【解决方案2】:
  • 如果一个类持有任何状态。然后它是@Autowired 的候选人 原型豆。每个请求都应该创建一个新的 bean。因此 它将为您提供所需的功能。例如POJO、实体、DTO

  • 如果一个类用于实用程序/行为并且不包含任何状态 将其标记为 @Autowired 默认 Singleton bean。例如服务、网关、控制器。

  • 如果一个类包含状态,但你不需要任何 Spring 该类中的功能。使用 new 关键字创建该对象/ 或 Some Factory.. @Autowired 用于 Spring 托管 bean。例如实体,POJO的

  • 如果一个类同时包含状态和行为方法。使用 SLP(单 责任原则并将其移至单独的类)

此外:

  1. Spring 在内部使用 servlet 线程,所有 Spring 托管的 bean 都是线程安全的(即由 Spring 框架创建的类)
  2. 谨慎使用 Spring bean 是您的责任。
  3. bean 的注入很棘手,即在 Prototype Bean 中注入一个 Singleton Bean。

【讨论】:

    【解决方案3】:

    Spring bean 不是线程安全的.......提供线程安全是您的责任。

    请参阅此处了解最佳做法:

    Spring bean thread safety

    【讨论】:

      【解决方案4】:

      如果您的@Service 必须存储状态,我建议您查看Command Pattern

      可以从Factory 创建命令,希望它是线程安全的,并通过“原型”范围提供给需要它的类。

      如果您想变得更花哨,可以查看CQRS (Command Query Responsibility Segregation)。 CQRS 不会帮助您处理线程,但它确实会改变命令的执行时间。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-04
        • 1970-01-01
        • 2018-05-10
        相关资源
        最近更新 更多