同步会话范围的spring-bean中的实例变量,以限制对旧服务的并发请求

时间:2013-02-15 07:56:51

标签: java spring concurrency httpsession

由于遗留系统不能同时处理来自同一用户的多个请求,我需要限制并发呼叫量。目标是将对服务的并发请求数限制为1 pr。用户(会话) - 但 使其阻止所有用户。我可以在客户端排队所有的ajaxrequests,但这似乎是一个只适用于某些调用的问题的大锤解决方案。如果可能的话,我想在服务器端解决这个问题。

替代。 1:可能的问题可能是自动服务的服务是代理 (由于requestcope)由spring注入并注入代理 引用可能会随请求而变化?或者Spring重用相同的代理 - 在这种情况下它会起作用吗?

@Scope("session")
public class Model {
    @Autowired
    Service service;

    public List<Pojo> getPojos() {
        synchronized(service) {
            if(!hasTriedToRetrievePojos) {
                hasTriedToRetrievePojos = true;
                service.getPojos();
            }
        }
    }
}


@Scope("request")
// Actually a LegacyService, wrapping an old legacysystem
public class Service {
    ...
}

替代。 2:如果Spring只构造了这个Model pr的一个实例。这应该按预期工作。

@Scope("session")
public class Model {
    private Object lock = new Object();

    @Autowired
    Service service;

    public List<Pojo> getPojos() {
        synchronized(lock) {
            if(!hasTriedToRetrievePojos) {
                hasTriedToRetrievePojos = true;
                service.getPojos();
            }
        }
    }
}

替代。 3:在Model中注入HttpSession并在HttpSession 属性 上手动同步(根据Is HttpSession thread safe, are set/get Attribute thread safe operations?中最受欢迎的答案)。没有春天的混乱,但更麻烦。

鉴于您使用粘性会话,我对会话参数的重新同步应该是安全的,即使在一个融合的环境中也是如此?

1 个答案:

答案 0 :(得分:0)

我赞成您的第二个解决方案,但在同步之前进行检查(这是昂贵的)并在同步块中进行另一次检查。

public List<Pojo> getPojos() {
     if (!hasTriedToRetrievePojos) {
         synchronized(lock) {
             if (!hasTriedToRetrievePojos) {
                 hasTriedToRetrievePojos = true;
                 service.getPojos();
             }
         }
     }
}

服务实例应该是单例,只要它在实例级别不包含任何用户/会话相关状态。

此解决方案的优势在于同步仅封装在Model中,并且不依赖于Service的正确配置(如第一个解决方案 - 例如服务上的@Scope("singleton")会导致不同的行为)。除此之外,第一个解决方案也应该有效。您可以使用@Scope("request")而不是@Scope("session")

如果粘性会话意味着用户的会话被绑定到一个appserver实例,并且每个用户的请求都被定向到这个实例,我会说是的,这是安全的。