首页 > 解决方案 > 任何服务器、框架或 J2EE 本身在 Java 中的任何地方仍然使用序列化吗?

问题描述

在“Serializable”类中有一个名为Fields 的Sonar 规则,它应该是瞬态的或可序列化的。当你向你的类添加一个不可序列化的字段时,它就会出现。该规则规定:

例如,在负载下,大多数 J2EE 应用程序框架将对象刷新到磁盘,并且据称具有非瞬态、不可序列化数据成员的可序列化对象可能导致程序崩溃,并为攻击者打开大门。

这对我来说听起来已经过时了。在Effective Java 3rd Edition中指出,在开发新软件时,序列化是不相关的。此外,从 Java 中删除序列化是 Oracle 的“长期目标”。Java 首席架构师 Mark Reinhold 本人表示

“序列化在 1997 年是一个可怕的错误。”</h3>

这个问题,如果 Spring 框架可以刷新对象,已经在这里问过:

所以我问一个问题: 任何现代应用服务器、框架或 J2EE 实现本身(尤其是与 CDI、EJB、JPA 交互的 Java 组件)是否在重负载下将对象刷新到磁盘?

还是这个说法已经过时了?

标签: javaserializationjakarta-eewildflysonarlint

解决方案


TL;博士

如果您没有实现可分发的 Web 应用程序,您没有启用会话持久性,并且您只使用内存中的缓存,那么您可能无需在任何地方都需要 Serializable。

解释

对于会话复制,Java 序列化仍然是最新的 Servlet 规范的必备条件:https ://jakarta.ee/specifications/servlet/5.0/jakarta-servlet-spec-5.0.html#distributed-environments

一个常见的用例是,如果您在负载均衡器后面有多个服务器,并且您在一个服务器上登录,您会得到一个 JSESSIONID cookie。如果负载均衡器将您发送到不同的服务器以进行下一个请求,您的登录属性和其他会话范围的属性将被序列化并复制到新服务器上,因此您的 JSESSIONID 在那里仍然有效。

另一个需要对会话范围属性进行序列化的用例是应用程序服务器决定将会话交换到磁盘时。例如 Tomcat 8,这可以配置为在有太多会话需要保存在内存中时激活,或者当服务器重新启动时,并且您希望保持会话处于活动状态。见 https://tomcat.apache.org/tomcat-9.0-doc/config/manager.html

对于这些类型的用例,每个 Servlet-5.0 兼容的应用程序服务器都必须默认支持 Http Sessions 中的 Serializable 对象。

对于某些服务器,这可以通过使用 Jackson-JSON 序列化或类似的东西来调整或覆盖。参见例如如何在 spring 中使用 jackson 而不是 JdkSerializationRedisSerializer

另一个常见的用例是缓存。这用于使对象尽可能快地访问,最好是在内存中,但可能会暂时卸载到磁盘或外部缓存服务器。它有一个标准 API (JSR-107) 明确选择不需要 Serializable 对象,但大多数实现仍然默认使用 java Serialization 作为卸载部分。

您可以再次调整这些以支持其他序列化机制,例如 ehcache:https ://www.ehcache.org/documentation/3.8/serializers-copiers.html


推荐阅读