Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Jsf 焊接和#x2B;GF4和x2B;会话处理:有时是错误的bean?_Jsf_Session_Glassfish_Cdi_Weld - Fatal编程技术网

Jsf 焊接和#x2B;GF4和x2B;会话处理:有时是错误的bean?

Jsf 焊接和#x2B;GF4和x2B;会话处理:有时是错误的bean?,jsf,session,glassfish,cdi,weld,Jsf,Session,Glassfish,Cdi,Weld,TL;DR我们得到了@SessionScopedbean实例,这些实例注入了另一个会话的内容 最近,我们的两个客户系统出现了严重问题。我们的客户正在两台机器上运行同一个JSF2.2应用程序的两个独立实例,这两台机器上有一台Glassfish 4.0服务器和WELD 2.0.5(真是内存泄漏!) 一些用户报告问题,例如提交表单后,响应显示的用户名与最初登录的用户名不同。由于我们无法在开发和测试环境中重现这种行为,我们开始从生产系统中获取日志数据 我们在记录什么? 在第一次尝试时,我们开始记录某个

TL;DR我们得到了
@SessionScoped
bean实例,这些实例注入了另一个会话的内容


最近,我们的两个客户系统出现了严重问题。我们的客户正在两台机器上运行同一个JSF2.2应用程序的两个独立实例,这两台机器上有一台Glassfish 4.0服务器和WELD 2.0.5(真是内存泄漏!)

一些用户报告问题,例如提交表单后,响应显示的用户名与最初登录的用户名不同。由于我们无法在开发和测试环境中重现这种行为,我们开始从生产系统中获取日志数据

我们在记录什么?

在第一次尝试时,我们开始记录某个用户在某个时间从哪个客户端执行了哪个操作。在对日志进行爬网后,我们发现了如下序列:

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
而替换用户(此处为
用户A
)的会话在替换发生之前并不总是结束(有时会导致一个用户注销另一个用户…)。那么,当前登录的用户存储在哪里?我们将其作为属性存储在
@SessionScoped
bean中,该bean被注入到
@RequestScoped
bean中,只要我们需要这些信息。这让我们得出了这样的理论:
@sessionscope
bean有时会混淆

@Named
@javax.enterprise.context.SessionScoped
public class SessionStateBean {
  private User user;

  public void setUser(...) { }
  public User getUser() { }
}
因此,在第二次尝试中,我们通过以下功能扩展了日志数据:

  • 我们开始将用户名存储在HTTP会话中,并在每个请求中将其与来自
    @SessionScoped
    bean的值进行比较
  • @SessionScoped
    bean的每个实例在构建和销毁bean以及更改用户属性时都会收到自己的UUID并记录。我们知道,
    @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()、Glassfish()、Grizzly()、JSF等方面遇到相同问题或已知错误的实际痕迹

所以我们的问题是:有没有人经历过类似的问题?不知何故,这种奇怪的行为是我们刚刚试图在错误的位置识别的已知错误吗?有没有真正的解决办法?任何暗示都将不胜感激

更新:我们发现,如果重新启动整个机器,所描述的行为将消失大约两周。如果我们只是重新启动Glassfish,那么这种奇怪的行为将在数小时内恢复。说真的,什么会严重影响Glassfish或JVM,以至于只有机器重新启动才会改变行为



目前,我们通过将保存在
@SessionScoped
bean中的所有数据直接放入HTTP会话来绕过这个问题,到目前为止,它似乎工作正常。但是这种方法太笨拙了…

而不是以这种方式注入会话范围的bean:

@Inject
private SessionBean sessionBean;
@Inject
private Instance<SessionBean> sessionBean;
尝试以这种方式注入:

@Inject
private SessionBean sessionBean;
@Inject
private Instance<SessionBean> sessionBean;
@Inject
私有实例sessionBean;

对于每次出现的僵尸会话,您能否确认正在使用新的JSESSION_ID,而不是重复使用旧的JSESSION_ID?使用JSF的
@sessionScope
是您的一个选项吗?是的,我可以确认会话ID不是旧会话ID的重复。我在上面的列表中添加了会话ID信息。JSF的
@SessionScope
对我们来说不是一个选项,因为它不能与所有其他CDI注释很好地结合在一起。我看到当CDI和JSF注释混合在一起时会发生一些非常奇怪的事情。您能否确认您的
@SessionScoped
bean确实是用
@javax.enterprise.context.SessionScoped
注释的,而不是
@javax.faces.bean.SessionScoped
?是的,我还可以确认正在使用的注释是
javax.enterprise.context.SessionScoped
。我刚才还注意到,bean没有显式的
serialVersionUID
。这对
@SessionScoped
bean很重要吗?