为什么HttpServlet要实现Serializable接口?

79

在我对Servlet的理解中,Servlet将由容器实例化,其init()方法将被调用一次,并且直到JVM关闭之前,Servlet将像单例一样存在。

我不希望我的Servlet被序列化,因为当应用程序服务器恢复或正常启动时,它将被新构造。Servlet不应该持有任何特定于会话的成员,因此将其写入磁盘并重新实例化是没有意义的。 这有什么实际用途吗?

我的担忧是,我在其中放置了一些不可序列化的字段,然后我的应用程序将在生产环境中出现神秘故障,其中将发生不同类型的会话复制。


类似:Web应用程序中序列化的目的 - Basil Bourque
5个回答

60

从技术上讲,我认为servlet容器可以像EJB会话bean一样将servlet对象写入磁盘进行"休眠"。因此,如果您的应用程序中存在非可序列化字段,您是正确的,需要问这个问题,以确定是否会导致应用程序失败。

实际上,在我的实践经验中,我从未听说过容器这样做,因此这只是早期J2EE时代的遗留问题。我不会担心它。


2
但是当一个Servlet应该是线程安全的,并且没有会话状态时,谁需要使其失活呢? - Amir Pashazadeh
1
为了使集群服务器不会失败并在出现故障时映射会话,类似的错误已经得到验证。https://issues.apache.org/bugzilla/show_bug.cgi?id=30809 - Dev
2
@dev 这个 bug 是关于非可序列化的会话属性,而不是关于任何 servlet 的序列化。 - Arend v. Reinersdorff
这个可以通过在 web.xml 中添加 <distributable /> 来触发。 - Archimedes Trajano
实际上我在现实生活中经历过这个问题:IBM Websphere正在做这件事... - Lonzak

11

HttpServlet 应该被序列化到磁盘并在 servlet 容器重新启动后继续存在。例如,Tomcat 允许您设置标志以启用此类继续存在。下一个选项是使用 JNDI 进行传输。这不是垃圾,它仅在极端情况下使用。


JNDI是设置不可序列化字段的唯一正确方式吗?这太可怕了。 :( - Hakanai

1

谷歌似乎暗示这样做是为了让容器作者有选择的权利,如果他们想要的话。

你说得对,Servlet 不应该持有任何特定于会话的成员,事实上我认为你希望尽可能少地保留状态。如果你把所有东西都存储在 Session 或 ServletConfig 中,我认为你可以在序列化时生存下来。


2
Session很可能会被序列化,而Servlet则不太可能,因此在那里存储不会缓解问题。 - skaffman
1
@matt b:关注点不是会话特定状态,而是servlet自身的依赖项(例如服务层对象)。 - Andrew Swan

0

就像Session对象被序列化以在支持集群选项的servlet容器中生存缓存一样,可能会有一个选项让容器将Servlet实例传输到另一个集群节点??我只是猜测


-3

Serializable被用作分布式环境中会话属性的标记接口。

SRV.7.7.2 分布式环境(JSR-154)
在应用程序标记为“可分发”的情况下,所有属于会话的请求必须由一个Java虚拟机(“JVM”)处理。容器必须能够适当地使用setAttribute或putValue方法处理放置在HttpSession类实例中的所有对象。出于满足这些条件的目的,将强制执行以下限制:
- 容器必须接受实现Serializable接口的对象。 - 会话迁移将由特定于容器的功能处理。
分布式Servlet容器必须对容器无法支持存储它们的会话的迁移所需机制的对象抛出IllegalArgumentException。
分布式Servlet容器必须支持必要的机制,以迁移实现Serializable的对象
(...)
容器提供者可以通过具有将分布式系统的任何活动节点的会话对象及其内容移至系统的不同节点的能力来确保可伸缩性和质量服务功能,如负载平衡和故障转移。如果分布式容器持久化或迁移会话以提供质量服务功能,则不限于使用本机JVM序列化机制对HttpSessions及其属性进行序列化。开发人员无法保证容器将调用会话属性上的readObject和writeObject方法(如果他们实现了),但是可以确保其属性的可序列化闭包将被保留。

3
这个回答是误导性的。通常情况下,一个Servlet实例并不会被存储在会话中。 - BalusC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接