我仍在学习适当的Java EE模式,并希望获得有关此问题的最佳工具的建议。
我有一个需要管理大量智能代理实例的系统。客户端可以按名称创建新实例或访问所需实例。多个客户端可以一次访问同一个代理。
我们的计划是通过REST接口向代理公开操作,因此调用可能类似于:
GET /sessions/
POST /sessions/{name}
PUT /sessions/{name}/doanaction
这些会话在重启后不会持续存在,所以我不是在寻找资源管理。
我的想法是我们可以使用@Singleton
会话bean来管理名称到代理的映射,然后将其注入到@Stateless
会话bean中,这些会话bean将为REST Web服务提供实用程序方法。
我想确保我不会在这里滥用@Singleton。由于多个客户端可以访问同一个代理,因此似乎没有任何方法可以使用Java EE会话管理来促进跨会话的对象管理。除了@Singleton Session bean之外还有其他可注射的对象吗?这通常是用于解决此问题的正确方法吗?提示赞赏!
答案 0 :(得分:1)
我认为EJB的任何开箱即用机制都不适合代理的概念 - 一个有状态的实体,它在服务器中拥有自己的生命周期,同时可供多个客户端访问。
无状态会话bean没有状态,有状态会话bean仅适用于一个客户端。
因此,可能的设计是将状态从代理提取到AgentState
对象。然后将每个代理的状态存储在ConcurrentHashMap
中,并按代理名称编制索引。哈希映射可以包装在@Singleton
bean中。
然后,REST控制器代码可以按名称检索代理状态,动态实例化代理new MyAgent(agentState)
将状态传递给它,然后执行某些操作。
多个客户端可以从缓存中同时检索代理状态。关键是MyAgent
代码需要通过在代理对象执行复合操作时锁定代理状态来防止代理状态的损坏:
类MyAgent {
public void someCompoundOperation() {
synchronized (agentState) {
...
String propertyA = agentState.getPropertyA();
... compare A with something
agentState.setPropertyA(newA);
...
}
}
当两个客户端读取相同的属性值并同时执行操作而不是等待其他代理完成并释放代理状态时,这将防止竞争条件。