【发布时间】:2009-08-04 16:08:27
【问题描述】:
据我了解,为了服务请求,Tomcat 可以创建任意数量的 servlet 副本。
这迫使我的 servlet 没有重量级状态,而是将所有状态存储在(单例)servlet 上下文中。
是否可以将 Tomcat 配置为将我的 servlet 视为单例,并且无论负载如何始终只引发一个 servlet 实例?
【问题讨论】:
据我了解,为了服务请求,Tomcat 可以创建任意数量的 servlet 副本。
这迫使我的 servlet 没有重量级状态,而是将所有状态存储在(单例)servlet 上下文中。
是否可以将 Tomcat 配置为将我的 servlet 视为单例,并且无论负载如何始终只引发一个 servlet 实例?
【问题讨论】:
根据 Servlet 规范,(v2.4,第 2.2 节“实例数”):
SRV.2.2 实例数
对于不在分布式环境中托管的 servlet(默认),servlet 每个 servlet 声明容器必须只使用一个实例。 但是,对于 servlet 实现
SingleThreadModel接口,servlet 容器可以 实例化多个实例以处理繁重的请求负载并序列化请求 到一个特定的实例。
您的问题的答案很简单:不要实现SingleThreadModel,也不要在web.xml 描述符文件中多次声明您的servlet。
【讨论】:
您不想在 Servlet 中存储状态的另一个主要原因是,如果您想在集群环境中运行,它会引入同步问题、序列化问题等。如果您不这样做,所有这些都很容易避免'不在 servlet 内部存储状态,而是在会话(或请求)对象中它所属的位置。
所以真的......你为什么要存储状态?出于某种原因,这是一种“推荐做法”。
【讨论】:
不,我不这么认为。然而,在实践中,tomcat 只会实例化一个 servlet,即使 JavaEE 规范允许它实例化多个。大多数(如果不是全部)MVC 框架都依赖于该假设,并将大量配置状态存储在 servlet 中。
如果您想安全起见,请不要将您的状态存储在 servlet 中,将其粘贴到另一个使用单例模式的类中,并从您的 servlet 中引用该单例。
【讨论】:
SingleThreadModel接口。
同上 Matt B。在我学到这一课之前,我被严重烧伤过一次。我将状态信息存储在 servlet 对象的静态中。在我们只有一台服务器的测试中,这一切都非常有效。然后我们部署到生产环境中,在那里我们有一个服务器集群,但在我们最终解决之前遇到了非常奇怪的错误。
使用您的 Session 或 Application 对象。这就是他们的目的。
故事的寓意:当结构的设计者提供了一个工具并说当你想做 X 时使用这个工具,这可能是有原因的。忽略此类建议要非常谨慎。
【讨论】: