我想知道制作会话Bean的最佳实践方式如何保证线程安全。
假设我有这个会话Bean及其服务:
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
class Cart {
private HashSet<Item> items = new HashSet<Item>();
private int counter = 0;
public HashSet<Item> getItems() {
return items;
}
public int getCounter() {
return counter;
}
}
@Service
class CartService {
@Autowired
private Cart cart;
public void addItem(Item item) throws FullException {
if (cart.getCounter() > 1234) {
throw new FullException();
}
cart.getItems().add(item);
}
}
上述代码不支持线程安全,在多个线程(同一个会话,例如异步Ajax请求)执行
CartService.addItem(Item)
时会出现问题。我认为我不是第一个遇到这个问题的人,但我的研究没有带给我最佳实践。
最糟糕的是,我可以在CartService中使addItem()同步,因为CartService被多个会话共享。在
CartService.addItem()
中对cart进行同步看起来对我来说同样糟糕,因为Cart是一个代理bean。这意味着我理解所有会话仍将在同一个对象上进行同步。一种可接受的解决方案似乎是在
CartService.addItem()
中对Cart.getItems()
进行同步块:@Service
class CartService {
@Autowired
private Cart cart;
public void addItem(Item item) {
synchronized(cart.getItems()) {
if (cart.getCounter() > 1234) {
throw new FullException();
}
cart.getItems().add(item);
}
}
}
有最佳实践吗?也许 Spring 在这个问题上有所建树?