簡體   English   中英

WELD + GF4 + SessionScoped:有時錯誤的bean?

[英]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() { }
}

因此,在第二次嘗試時,我們通過以下功能擴展了日志數據:

  • 我們開始在HTTP會話中存儲用戶名,並在每個請求中將其與來自@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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM