這是我的場景:我可以訪問Hibernate事件偵聽器中的FacesContext嗎?
我有my-jsf-app.war(JSF 1.2應用程序)和daos-and-entities.har(Hibernate 3.3.1)部署到JBOSSAS 5服務器。我想要的是在我的應用程序中有某種更改日誌,其中包含「誰進行了更改」的信息。所以我的想法是讓hibernate事件監聽器訪問FacesContext(或者實際上在上下文中的HttpSession)來檢索當前登錄的用戶。
所以基本上我配置了事件偵聽器並添加了以下方法來檢索當前登錄的用戶。
protected static String tryToFindUserLogin() {
try {
Class classFacesContext = Class.forName("javax.faces.context.FacesContext");
Class classExternalContext = Class.forName("javax.faces.context.ExternalContext");
Method methodGetCurrentInstance = classFacesContext.getMethod("getCurrentInstance", (Class[])null);
Method methodGetExternalContext = classFacesContext.getMethod("getExternalContext", (Class[])null);
Method methodGetRemoteUser = classExternalContext.getMethod("getRemoteUser", (Class[])null);
// This call always returns null
Object currentFacesContext = methodGetCurrentInstance.invoke(null, (Object[])null);
Object currentExternalContext = methodGetExternalContext.invoke(currentFacesContext, (Object[])null);
String login = (String) methodGetRemoteUser.invoke(currentExternalContext, (Object[])null);
logger.debug("Found Weblogin: " + login);
return login;
} catch (Exception e) {
logger.debug(e, e);
}
return "anonymous";
}
我使用java反射來做到這一點,因爲HAR文件也用於其他非jsf項目。
問題是我從來沒有得到currentFacesContext。我明白FacesContext.getCurrentInstance()是ThreadLocal。但是,如果在JSF ManagedBean action方法中直接觸發hibernate操作(例如saveOrUpdate()),那麼事件監聽器不應該與action方法執行相同的線程嗎?
任何幫助都很有價值,也許對於我的場景還有一種完全不同的方法,我不知道。我顯然不想爲我所有的dao調用添加一個userContext參數,因爲這將是一項大量的工作。提前
我已經看到了與EclipseLink和JSF類似的工作,所以它應該是可能的。 嘗試使用調試器進行單步調試 - 在事件監聽器上設置斷點並查看堆棧跟蹤的外觀。這至少會證實你對範圍的假設(這似乎是合理的),事件偵聽器將在JSF請求的範圍內運行,以便FacesContext被綁定。 其他要嘗試的事情:使用常規方法調用而不反射;擺脫「靜態」;或者將監聽器放入web應用程序本身。也許一些微妙的類加載器層次結構問題。 – wrschneider
感謝提示類加載器問題,這導致我找到了解決方案。我會發佈一個答案。 – huo73