WELD + GF4 + SessionScoped:有时会错误的bean? [英] WELD + GF4 + SessionScoped: Sometimes wrong bean?

查看:112
本文介绍了WELD + GF4 + SessionScoped:有时会错误的bean?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



TL; DR 我们得到了 @SessionScoped 会话




最近,我们的两个客户系统遇到了严重的问题。我们的客户在两台拥有带WELD 2.0.5的Glassfish 4.0服务器的机器上运行同一个JSF 2.2应用程序的两个独立实例(对内存泄漏记忆犹新!)。

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



我们记录的是什么? 在我们的第一次尝试中,我们开始记录哪个用户从哪个客户端有些时候。在浏览日志后,我们发现了如下的序列:

 时间客户端用户操作
....... ......................
t = 0 ClientA UserA登录
t = 1 ClientA UserA注销
t = 2 ClientB UserB登录
t = 3 ClientB UserB ActionA
t = 4 ClientB * UserA * ActionB
t = 5 ClientB UserB Logoff

在更换发生之前,替换用户的会话(这里 User A )并不总是结束(有时会导致一个用户注销另一个用户...)。那么当前登录的用户存储在哪里?我们将它作为一个属性存储在一个 @SessionScoped bean中,并被注入到 @RequestScoped bean中,只要我们需要这些信息。这导致我们理解 @SessionScoped bean有时会混淆。

  @Named 
@ javax.enterprise.context.SessionScoped
public class SessionStateBean {
private用户用户;

public void setUser(...){}
public User getUser(){}
}



  • 我们开始在HTTP会话中存储用户名,并将它在每个请求中与来自 @SessionScoped bean的值进行比较。

  • 每个 @SessionScoped bean实例都收到它自己的UUID,并在bean构建时记录下来&销毁以及用户资产被更改时。我们知道 @SessionScoped bean可能有多个代理,被钝化等,但我们试了一下。



关于第一个日志功能,我们开始看到序列显示来自session scoped bean的用户名和存储在HTTP session内的值之间的实际差异:

 时间会话客户端用户操作
..................... ........
t = 0 SessA ClientA UserA登录
t = 1 SessA ClientA UserA Logoff
t = 2 SessB ClientB UserB登录
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 事件,观察到如下序列:

 时间会话Bean操作UserValue 
................................
t = 0 SessA BeanA构造(null )
t = 1 SessA BeanA SetUser UserA // login
t = 2 SessA BeanA SetUser(null)//注销
t = 3 SessA BeanA Destroy(null)
//到目前为止好,现在它变得有趣
t = 4 SessB BeanA SetUser UserB //登录
t = 5 SessB BeanA SetUser(null)//注销
t = 6 SessC BeanA SetUser UserC // login
t = 7 SessC BeanA SetUser(null)//注销
t = 8 SessD BeanA SetUser UserD //登录
t = 9 SessD BeanA SetUser(null)//注销

我们没有想到有时在 @PreDestroy 事件bean实例获得重用之后没有经历建设和破坏的生命周期。考虑到所有记录的bean实例, 500(系统A)至4000(系统B)中的1个bean。当会话范围值和HTTP会话值不同时,这并不总是发生,但总是当我们看到这样的一个bean实例被重用时,它就是值的不同。



最初我们认为这些事件更有可能发生在服务器负载一段时间后,但事实证明这并非如此。有时它们会在最后一次服务器重启后几小时发生,有时会在两周后发生。

通过在互联网上搜索这些问题,我们无法找到其他遇到相同问题或WELD中已知错误的人的实际痕迹(<​​a href =https: //issues.jboss.org/browse/WELD-1691rel =noreferrer>最好的痕迹,但错误的版本),Glassfish,Grizzly(最好的追踪,但太旧了),JSF等等

是:有没有人遇到过类似的问题?这种奇怪的行为是不是某种我们试图在错误的地方发现的已知错误?是否有一个实际的修复?任何提示都非常感谢!



更新: 我们发现,如果我们重新启动整个机器,已经过去了两个星期左右。如果我们只是重新启动Glassfish,那么在奇怪的行为回来之前,这只是一个小时的问题。严重的是,什么会影响Glassfish或JVM,使得只有机器重启才会改变行为?






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

解决方案

而不是像这样注入session scoped bean:

  @Inject 
private SessionBean sessionBean;

试着用这种方式注入它:

  @Inject 
private实例< SessionBean>一个sessionBean;



TL;DR We get @SessionScoped bean instances injected that have the content of another session


lately we have been experiencing serious problems with two of our customer systems. Our customers are running two independent instances of the same JSF 2.2 application on two machines having a Glassfish 4.0 Server with WELD 2.0.5 (hail to the memory leak!).

Some users have been reporting problems that after e.g. submitting a form the response shows another user name than the one who initially logged in. Since we were unable to reproduce this behaviour in our development and testing environments, we started to grab log data from the productive systems.

What were we logging?

On our first attempt we started logging which user conducted which action from which client at some time. After crawling through the logs we found sequences like this:

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

Whereas the session of the replacing user (here User A) was not always over before the replacement happened (sometimes resulting in one user logging out another one...). So where is the currently logged in user stored? We store it as a property in a @SessionScoped bean being injected into @RequestScoped beans wherever we need this information. This led us to the theory that the @SessionScoped beans sometimes get mixed up.

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

  public void setUser(...) { }
  public User getUser() { }
}

Therefore on our second attempt we extended the log data by the following features:

  • We started storing the user name inside the HTTP session and compared it on every request with the value coming from the @SessionScoped bean.
  • Every instance of the @SessionScoped bean received its own UUID and logged when the bean was constructed & destroyed as well as when the user property was changed. We know that it is possible that @SessionScoped beans can have multiple proxies, be passivated, etc., but we gave it a try.

Regarding the first log feature we started seeing sequences showing actual differences between the user name coming from the session scoped bean and the value being stored inside the HTTP session:

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

Taking all requests being processed into account, the ones where the session scope value does not match the session value are approx. 1 out of 60 to 150 requests.

More interesting is what happened with the @SessionScoped bean instances. Since we are tracking @PostConstruct & @PreDestroy events, sequences like the following were observed:

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

We did not expect that sometimes after the @PreDestroy event bean instances get reused without going through the life cycle of construction and destruction. Taking all logged bean instances into account this happens with approx. 1 bean out of 500 (System A) to 4000 (System B). This is not always happening when the session scope value and the HTTP session value differ, but always when we see such a bean instance being reused it is when the values are different.

Initially we assumed that these events are more likely to occur after the server has been under load for a while, but this turned out not to be true. Sometimes they occur some hours after the last server restart and sometimes after two weeks.

Searching the internet for these issues we were not able to find actual traces on other people experiencing the same problems or known bugs in either WELD (best trace, but wrong version), Glassfish, Grizzly (best trace, but too old), JSF, etc.

So our question is: Is there anyone who ever has experienced a similar problem? Is this odd behaviour somehow a known bug we just tried to identify in the wrong spot? Is there even an actual fix? Any hint is gladly appreciated!

Update: We found out that if we restart the whole machine the described behaviour is gone for around two weeks. If we just restart Glassfish it's a matter of hours until the odd behaviour is back. Seriously, what can affect Glassfish or the JVM that badly such that only a machine reboot changes the behaviour?


Currently we are bypassing the problem by putting all data we kept in the @SessionScoped bean directly into the HTTP session and so far it seems to work fine. But that approach is so clumsy...

解决方案

Instead of injecting the session scoped bean this way:

@Inject
private SessionBean sessionBean;

Try to inject it this way:

@Inject
private Instance<SessionBean> sessionBean;

这篇关于WELD + GF4 + SessionScoped:有时会错误的bean?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆