在我对 Servlet 的理解中,Servlet 会被 Container 实例化,它的init()
方法会被调用一次,并且 Servlet 会像单例一样存活,直到 JVM 关闭。
我不希望我的 servlet 被序列化,因为它会在应用服务器恢复或正常启动时重新构建。servlet 不应包含特定于会话的成员,因此将其写入磁盘并重新实例化是没有意义的。这有实际用途吗?
我担心的是,我在其中放置了一些不可序列化的字段,然后我的应用程序将在将发生不同类型的会话复制的生产环境中神秘地失败。
在我对 Servlet 的理解中,Servlet 会被 Container 实例化,它的init()
方法会被调用一次,并且 Servlet 会像单例一样存活,直到 JVM 关闭。
我不希望我的 servlet 被序列化,因为它会在应用服务器恢复或正常启动时重新构建。servlet 不应包含特定于会话的成员,因此将其写入磁盘并重新实例化是没有意义的。这有实际用途吗?
我担心的是,我在其中放置了一些不可序列化的字段,然后我的应用程序将在将发生不同类型的会话复制的生产环境中神秘地失败。
从技术上讲,我相信允许 servlet 容器将 servlet 对象“钝化”到磁盘,这与 EJB 会话 bean 可以采用的方式类似。因此,如果您的应用程序由于不可序列化的字段而失败,您问这个问题是正确的。
在实践中,我从未听说过容器会这样做,所以它实际上只是早期 J2EE 糟糕的旧时代遗留下来的包袱。我不会担心的。
HttpServlet 应该通过序列化到磁盘并在 servlet 容器重新启动后继续存在。例如,tomcat 允许您设置启用这种生存的标志。下一个选项是使用 JNDI 传输。这不是垃圾,它仅用于极端用例。
谷歌似乎建议这样做是为了让容器作者可以选择,如果他们想要的话。
您是正确的,servlet 不应该包含特定于会话的成员,实际上我认为您希望尽可能少的状态。如果您将所有内容存储在 Session 或 ServletConfig 中,我认为您将能够在序列化中幸存下来。
就像 Session 对象被序列化以在那些提供集群选项的 servlet 容器的缓存中存活一样,容器可能有一个选项可以将 Servlet 实例也传输到另一个集群节点?我只是在这里猜测
Serializable 用作分布式环境中会话属性的标记接口。
SRV.7.7.2 分布式环境 (JSR-154)
在标记为可分发的应用程序中,作为会话一部分的所有请求必须一次由一个 Java 虚拟机 (“JVM”) 处理。容器必须能够适当地使用 setAttribute 或 putValue 方法处理放置在 HttpSession 类实例中的所有对象。为了满足这些条件,施加了以下限制:
- 容器必须接受实现 Serializable 接口的对象。
- 会话的迁移将由特定于容器的设施处理。
分布式 servlet 容器必须为容器不能支持迁移存储它们的会话所必需的机制的对象抛出 IllegalArgumentException 。
分布式 servlet 容器必须支持 迁移实现 Serializable 的对象所必需的机制。
(...)
容器提供者可以通过将会话对象及其内容从分布式系统的任何活动节点移动到系统的不同节点的能力来确保负载平衡和故障转移等服务特性的可扩展性和质量。如果分布式容器持久化或迁移会话以提供服务质量特性,则它们不限于使用本机 JVM 序列化机制来序列化 HttpSession 及其属性。开发人员不能保证容器在实现会话属性时会调用它们的 readObject 和 writeObject 方法,但可以保证它们的属性的 Serializable 闭包将被保留。