TL; DR 我们注入的@SessionScoped
bean实例具有另一个会话的内容
最近我们遇到了两个客户系统的严重问题。我们的客户在具有WELD 2.0.5的Glassfish 4.0服务器的两台机器上运行相同JSF 2.2应用程序的两个独立实例(因内存泄漏而欢呼!)。
有些用户报告了以下问题:提交表单时,响应显示的用户名与最初登录的用户名不同。由于我们无法在开发和测试环境中重现此行为,因此我们开始从生产系统中获取日志数据。
我们记录了什么?
在我们第一次尝试时,我们开始记录哪个用户在某个时间从哪个客户执行了哪个操作。爬过日志后,我们发现了如下序列:
Time Client User Action
.............................
t=0 ClientA UserA Login
t=1 ClientA UserA Logoff
t=2 ClientB UserB Login
t=3 ClientB UserB ActionA
t=4 ClientB *UserA* ActionB
t=5 ClientB UserB Logoff
替换用户的会话(此处User A
)在更换发生之前并不总是结束(有时会导致一个用户注销另一个用户......)。那么当前登录的用户存储在哪里?我们将它作为一个属性存储在@SessionScoped
bean中,只要我们需要这些信息,就会注入@RequestScoped
bean。这导致我们认为@SessionScoped
豆子有时混淆了。
@Named
@javax.enterprise.context.SessionScoped
public class SessionStateBean {
private User user;
public void setUser(...) { }
public User getUser() { }
}
因此,在第二次尝试时,我们通过以下功能扩展了日志数据:
@SessionScoped
bean的值进行比较。@SessionScoped
bean的每个实例都接收到自己的UUID,并在构建bean时记录。销毁以及用户属性更改时。我们知道@SessionScoped
bean可能有多个代理,被钝化等等,但我们试了一下。关于第一个日志功能,我们开始看到序列显示来自会话范围bean的用户名与存储在HTTP会话中的值之间的实际差异:
Time Session Client User Action
.............................
t=0 SessA ClientA UserA Login
t=1 SessA ClientA UserA Logoff
t=2 SessB ClientB UserB Login
t=3 SessB ClientB UserB ActionA
t=4 |SessB ClientB *UserA* ActionB
+-> SessionScope != Session
t=5 SessB ClientB UserB Logoff
将所有正在处理的请求考虑在内,会话范围值与会话值不匹配的请求大约为。 60到150个请求中的1个。
更有趣的是@SessionScoped
bean实例发生了什么。由于我们正在追踪@PostConstruct
&发现了@PreDestroy
个事件,如下所示的序列:
Time Session Bean Action UserValue
................................
t=0 SessA BeanA Construct (null)
t=1 SessA BeanA SetUser UserA // login
t=2 SessA BeanA SetUser (null) // logout
t=3 SessA BeanA Destroy (null)
// so far so good, now it gets interesting
t=4 SessB BeanA SetUser UserB // login
t=5 SessB BeanA SetUser (null) // logout
t=6 SessC BeanA SetUser UserC // login
t=7 SessC BeanA SetUser (null) // logout
t=8 SessD BeanA SetUser UserD // login
t=9 SessD BeanA SetUser (null) // logout
我们没有想到有时候@PreDestroy
事件bean实例得到重用而不经历构建和销毁的生命周期。将所有已记录的bean实例考虑在内,这种情况大约发生。从500(系统A)到4000(系统B)中的1个bean。当会话范围值和HTTP会话值不同时,并不总是发生这种情况,但总是当我们看到这样的bean实例被重用时,它就是值不同的时候。
最初我们假设这些事件更有可能在服务器加载一段时间后发生,但事实证明并非如此。有时它们在最后一次服务器重启后几个小时发生,有时在两周后发生。
在互联网上搜索这些问题时,我们无法在WELD(best trace, but wrong version),Glassfish,Grizzly(best trace, but too old),JSF中找到遇到相同问题或已知错误的其他人的实际痕迹等等。
所以我们的问题是:有没有人遇到类似的问题?这个奇怪的行为是不是一个已知的错误,我们只是试图在错误的位置识别?有没有实际修复?很高兴有任何提示!
更新: 我们发现,如果我们重启整台机器,所描述的行为将会持续两周左右。如果我们只是重启Glassfish,那么奇怪的行为又回来了几个小时。严重的是,什么可能会严重影响Glassfish或JVM,只有机器重新启动会改变行为?
目前我们通过将我们保存在@SessionScoped
bean中的所有数据直接放入HTTP会话来绕过这个问题,到目前为止似乎工作正常。但那种做法太笨拙......
答案 0 :(得分:0)
而不是以这种方式注入会话范围的bean:
@Inject
private SessionBean sessionBean;
尝试以这种方式注入:
@Inject
private Instance<SessionBean> sessionBean;