Tomcat中Session对象部分属性值丢失问题的分析与解决

服务器
无论是变成NULL的属性,还是未变成NULL的属性,都是最简单的String类型变量,实在让人看不明白他们之间到底有何不同。

我们最近的一个 Java 项目在从开发环境迁移到测试环境之后,遇到了一个非常诡异的问题——在将一个 Java 对象存储到 SESSION 会话中而后从中取出时,这个对象的部分属性在 SESSION 会话刚创建的一段时间内是正确的,但是一段时间过后,虽然SESSION没有失效,但是这部分属性的值却变成NULL了。更令人奇怪的是,无论是变成NULL的属性,还是未变成NULL的属性,都是最简单的String类型变量,实在让人看不明白他们之间到底有何不同。

[[208778]]

为了将问题表述清楚,下面我举个例子来详细说明下。我们定义的类信息大概如下图所示:

其中,SessionBean是我们将要放到SESSION中的对象,而BaseBean则是SessionBean继承的父类。无论是在开发还是测试环境,SessionBean对象都可以不抛出任何异常地存取值,但是其中的属性则不一定:属性a和属性b在SESSION创建之后,只要SESSION没有失效,就一直可以正常读取其值;但是其中的属性c,只在SESSION创建不久的一段时间内有效,如果一段时间后再取值,属性c的值就变成NULL了。没有任何认为操作,变量值却改变了,是不是很神奇?

【问题根源】

中间的具体排查过程我就不讲了,反正经过好长一段时间的分析和排查,问题的根源终于找到了—— BaseBean没有继承Serializable接口!

【原因剖析】

下面我结合上文以及我对 Tomcat 服务器SESSION会话管理原理的分析,来给大家解释下,为什么仅仅少继承了一个可序列化接口(Serializable),就会出现如此诡异的问题。

首先,在SESSION创建的时候,SessionBean对象中的所有属性(a、b、c),都可以正常写入到SESSION会话中,这点是没有问题的。对于刚刚创建的SESSION,此时其内容都保存在服务器的内存当中,如果这时候读取SEESION, Tomcat 直接把内存中的内容返回给调用者就OK了,所以返回的属性值都是正确的。

而后,无论是因为Tomcat占用内存超出了阈值也好,还是Tomcat定期保存SESSION现场也罢,反正都会引起接下来的操作——将SESSION会话持久化。在将数据从内存写入硬盘的过程中,就涉及了一个非常重要的问题:数据要写入硬盘,应该以什么样的格式存储,又应该怎样把它变成相应的格式?这就是——序列化!

通过观察上图中的代码我们不难发现,SessionBean对象已经实现了Serializable接口,所以在将SessionBean对象保存到磁盘的过程中,也就是对对象进行序列化操作的时候,是不会报任何错误的,这也是我们难以通过跟踪错误日志来定位问题的根本原因。但是因为SessionBean的基类BaseBean没有实现Serializable接口,所以BaseBean中的属性c在进行序列化的时候就没能保存下来,进而在反序列化的时候,属性c的值就变成NULL了。所以我们读出的值也莫名其妙变成了NULL也就不难理解了。

【解决方案】

至于解决方案,很简单,给基类BaseBean加个Serializable接口就搞定了嘛。

【问题反思】

此次问题带给我们的反思主要有两个:

***,对于SESSION会话中保存的类,一定要确保该类以及该类的父类实现了Serializable接口,否则无法将类中的属性序列化。

第二,在进行业务逻辑操作之前,一定要对所有具有不确定性的值的合法性进行安全校验(防御性编程),此次若不是我“多此一举”,在业务逻辑前对这个基本可以认定***正确(因为写入完全可控可信)的属性c进行了合法性校验,这个神奇的问题还说不定什么时候才能发现呢。所以说,防御性编程很重要。

责任编辑:武晓燕 来源: 马文建的博客
相关推荐

2009-07-09 09:46:55

session过期Ajax

2009-07-22 17:37:06

ASP.NET Ses

2017-09-12 08:31:57

PHPSession方法

2011-04-08 14:04:13

IE9HTML5

2009-07-01 16:26:10

jsp web开发

2010-06-30 14:15:08

SQL Server死

2019-05-15 15:10:12

Tomcat Session Cookie

2009-06-03 15:50:51

eclipse中启动超eclipsetomcat

2017-12-04 10:56:47

MySQL问题分析解决对策

2024-06-05 06:37:19

2013-06-28 14:00:28

Android

2019-12-31 14:59:06

TomcatNIOJava

2009-12-18 15:19:50

2022-07-14 14:27:34

Javascript数字精度二进制

2011-08-25 17:36:23

并发数据库丢失修改问题

2014-08-18 09:31:15

2010-04-22 09:08:30

Oracle 8i

2009-06-16 14:08:10

JBoss JDBC驱

2024-09-05 14:25:35

2021-02-04 09:13:03

Session异步线程
点赞
收藏

51CTO技术栈公众号