由于遗留系统不能同时处理来自同一用户的多个请求,我需要限制并发调用的数量。目标是将服务的并发请求数限制为 1 pr。用户( session )- 但不 阻止所有用户。我可以在客户端对所有 ajax 请求进行排队,但这似乎是解决仅适用于某些调用的问题的大锤解决方案。如果可能的话,我想在服务器端解决这个问题。
替代品。 1:可能的问题可能是 Autowiring 服务是代理 (由于 requestscope)由 spring 注入(inject)并且注入(inject)的代理 引用可能会因请求而改变?或者 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。 session 这应该按预期工作。
@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:在模型中注入(inject) HttpSession 并在 HttpSession property 上手动同步(根据 Is HttpSession thread safe, are set/get Attribute thread safe operations? 中最受欢迎的答案)。没有spring的困惑,反而比较繁琐。
鉴于您使用粘性 session ,我认为即使在集群环境中, session 参数的同步也应该是安全的?
最佳答案
我赞成您的第二个解决方案,但在同步之前进行检查(这很昂贵)并在同步块(synchronized block)中进行另一次检查。
public List<Pojo> getPojos() {
if (!hasTriedToRetrievePojos) {
synchronized(lock) {
if (!hasTriedToRetrievePojos) {
hasTriedToRetrievePojos = true;
service.getPojos();
}
}
}
}
只要服务实例在其实例级别不包含任何用户/ session 相关状态,就应该是单例的。
此解决方案的优点是同步仅封装在 Model
中,不依赖于 Service
的正确配置(如第一个解决方案 - 例如 @Scope("singleton")
在服务上会导致不同的行为)。除此之外,第一个解决方案也应该有效。您可以使用 @Scope("session")
而不是 @Scope("request")
。
如果粘性 session 意味着用户的 session 绑定(bind)到一个应用程序服务器实例,并且该用户的每个请求都定向到该实例,我会说是的,它是安全的。
关于java - 在 session 范围内的 spring-bean 中同步实例变量以限制对遗留服务的并发请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14890348/