![](/img/trans.png)
[英]Wildfly 8.2 + JSF + SessionScoped : sometimes wrong data returned
[英]WELD + GF4 + SessionScoped: Sometimes wrong bean?
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
bean有時會混淆的理論。
@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( 最佳痕跡,但錯誤版本 ),Glassfish,Grizzly( 最佳痕跡,但太舊 ),JSF,等等
所以我們的問題是:有沒有人經歷過類似的問題? 這個奇怪的行為是不是一個已知的錯誤,我們只是試圖在錯誤的位置識別? 有沒有實際修復? 任何提示都很高興!
更新:我們發現,如果我們重新啟動整台機器,所描述的行為將持續兩周左右。 如果我們只是重啟Glassfish,那么奇怪的行為又回來了幾個小時。 嚴重的是,什么能夠嚴重影響Glassfish或JVM,只有機器重啟會改變行為?
目前我們通過將保存在@SessionScoped
bean中的所有數據直接放入HTTP會話來繞過這個問題,到目前為止它似乎工作正常。 但那種方法太笨拙了......
而不是以這種方式注入會話范圍的bean:
@Inject
private SessionBean sessionBean;
嘗試以這種方式注入:
@Inject
private Instance<SessionBean> sessionBean;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.