mar*_*383 7 session jsf glassfish cdi weld
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
Run Code Online (Sandbox Code Playgroud)
User A在更换发生之前,替换用户(此处)的会话并不总是结束(有时会导致一个用户注销另一个用户......).那么当前登录的用户存储在哪里?我们将它作为属性存储在@SessionScopedbean中,@RequestScoped只要我们需要这些信息,就会将其存入bean中.这导致我们认为@SessionScoped豆类有时会混淆的理论.
@Named
@javax.enterprise.context.SessionScoped
public class SessionStateBean {
private User user;
public void setUser(...) { }
public User getUser() { }
}
Run Code Online (Sandbox Code Playgroud)
因此,在第二次尝试时,我们通过以下功能扩展了日志数据:
@SessionScopedbean 的值进行比较.@SessionScopedbean的每个实例都接收到自己的UUID,并在构造和销毁bean以及更改用户属性时记录.我们知道@SessionScopedbean有可能有多个代理,被钝化等等,但我们试了一下.关于第一个日志功能,我们开始看到序列显示来自会话范围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
Run Code Online (Sandbox Code Playgroud)
考虑到正在处理的所有请求,会话范围值与会话值不匹配的请求大约为.60到150个请求中的1个.
更有趣的是@SessionScopedbean实例发生了什么.由于我们正在跟踪@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
Run Code Online (Sandbox Code Playgroud)
我们没想到有时在@PreDestroy事件bean实例被重用之后却没有经过构建和破坏的生命周期.将所有记录的bean实例考虑在内,这种情况大约发生.从500(系统A)到4000(系统B)中的1个bean.当会话范围值和HTTP会话值不同时,这并不总是发生,但是当我们看到这样的bean实例被重用时,它总是在值不同时发生.
最初我们假设这些事件更有可能在服务器负载一段时间后发生,但事实证明并非如此.有时它们在最后一次服务器重启后几个小时发生,有时在两周后发生.
在互联网上搜索这些问题,我们无法找到遇到相同问题的其他人的实际痕迹或WELD(最佳痕迹,但错误版本),Glassfish,Grizzly(最佳痕迹,但太旧),JSF,等等
所以我们的问题是:有没有人经历过类似的问题?这个奇怪的行为是不是一个已知的错误,我们只是试图在错误的位置识别?有没有实际修复?任何提示都很高兴!
更新:我们发现,如果我们重新启动整台机器,所描述的行为将持续两周左右.如果我们只是重启Glassfish,那么奇怪的行为又回来了几个小时.严重的是,什么能够严重影响Glassfish或JVM,只有机器重启会改变行为?
目前我们通过将我们保存在@SessionScopedbean 中的所有数据直接放入HTTP会话来绕过这个问题,到目前为止它似乎工作正常.但那种方法太笨拙了......
小智 0
不要以这种方式注入会话作用域 bean:
@Inject
private SessionBean sessionBean;
Run Code Online (Sandbox Code Playgroud)
尝试这样注入:
@Inject
private Instance<SessionBean> sessionBean;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1145 次 |
| 最近记录: |