以下是我的情景:
我将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动作方法中直接触发了hibernate动作(例如saveOrUpdate()),那么事件监听器不应该与动作方法相同的线程执行吗?
任何帮助都是适用的,也许我的方案也有一种完全不同的方法,我不知道。我显然不想在我的所有dao调用中添加userContext参数,因为这将是一项巨大的工作。
提前谢谢
答案 0 :(得分:1)
获得有价值的提示后,我找到了解决方案。 WAR在其WEB-INF \ lib中包含JSF实现JAR。由于WAR和HAR是单独的部署,它们使用单独的类加载器,这导致WAR从其WEB-INF \ lib加载JSF实现,而HAR从JBOSS安装加载它。
我可以通过以下方式更改上述代码来强制使用正确的类加载器:
protected static String tryToFindUserLogin() {
try {
/*** Obtain the classLoader from the calling Thread, instead of using the default ***/
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class classFacesContext = classLoader.loadClass("javax.faces.context.FacesContext");
Class classExternalContext = classLoader.loadClass("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);
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 (Throwable e) {
logger.debug(e, e);
}
return "anonymous";
}
另外我将catch块更改为catch(Throwable),因为如果在非JSF环境中运行,getMethod()可能会抛出一个RuntimeException,它不会被catch捕获(异常)
这完美无缺!