似乎可以在JSF的恢复视图阶段重用UIViewRoot对象,如link here
中所建议的那样我正在处理一个包含数百个数据元素的非常大的表单,并且在对应用程序进行概要分析时,我发现RestoreView阶段花费的时间最长。
因此,按照这个建议,我尝试在会话对象中缓存UIViewRoot对象,它似乎可以正常工作并提高性能。
但我需要知道的是,它会导致框架出现任何问题(类似陈旧数据或任何其他已知问题)。
是否有其他方法可以缓存View Root。
每次调用FullVisitContext时,都需要很长时间,PartialVisitContext对我不起作用。
这是我在视图处理程序
中编写的内容 package com.app.customviewhandler;
import java.io.IOException;
import java.util.Enumeration;
import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.application.ViewHandlerWrapper;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import configuration.ComponentConfigurationContext;
import configuration.ComponentConfigurationFactory;
import logging.LoggingService;
import com.app.common.utilities.StringUtils;
public class CustomViewHandler extends ViewHandlerWrapper {
private ViewHandler wrapped;
private static LoggingService loggingService;
private static final String _USER_CURRENT_VIEW_ID = "USER_CURRENT_VIEW_ID";
private static final String _CURRENT_REQUEST_URI = "CURRENT_REQUEST_URI";
private static final String _PREVIOUS_REQUEST_URI = "PREVIOUS_REQUEST_URI";
static {
ComponentConfigurationContext ctx = ComponentConfigurationFactory.getInstance().getComponentConfigurationContext();
loggingService = (LoggingService) ctx.getObject("loggingService");
}
/**
*
*/
public CustomViewHandler(ViewHandler wrapped) {
this.wrapped = wrapped;
loggingService.info(this, "JSF: Registered a new instance of CustomViewHandler");
}
public UIViewRoot restoreView(FacesContext context, String viewId) {
try {
loggingService.info(this, "JSF: restoreView: start");
HttpSession session = (HttpSession) context.getCurrentInstance().getExternalContext().getSession(true);
HttpServletRequest request = (HttpServletRequest) context.getCurrentInstance().getExternalContext().getRequest();
/**
* Whenever an URL redirection occurs, we have to reset the cache
*/
/**
* Set the current view name
*/
request.setAttribute(_USER_CURRENT_VIEW_ID, viewId);
loggingService.info(this, "JSF: restoreView: setting _USER_CURRENT_VIEW_ID[" + viewId + "]");
UIViewRoot cachedView = null;
String previousRequestURI = (String)session.getAttribute(_PREVIOUS_REQUEST_URI);
String currentRequestURI = request.getRequestURI();
if(StringUtils.checkNullOrEmpty(previousRequestURI)){
loggingService.info(this, "JSF: restoreView: _PREVIOUS_REQUEST_URI is null");
resetCachedView(context);
}else{
loggingService.info(this, "JSF: restoreView: _PREVIOUS_REQUEST_URI["+previousRequestURI+"] for viewId[" + viewId + "]");
if(StringUtils.checkNullOrEmpty(currentRequestURI)){
loggingService.info(this, "JSF: restoreView: current request does not have any requestURI for viewId[" + viewId + "]");
resetCachedView(context);
}else{
if(!previousRequestURI.equalsIgnoreCase(currentRequestURI)){
loggingService.info(this, "JSF: restoreView: URL redurection has occured. resetCachedViews()");
resetCachedView(context);
}else{
loggingService.info(this, "JSF: restoreView: URL same URI requested["+currentRequestURI+"] for viewId[" + viewId + "]");
cachedView = (UIViewRoot) (session.getAttribute(viewId));
}
}
}
if (cachedView == null) {
loggingService.info(this, "JSF: restoreView: cachedView is null. So the view will be restored now");
cachedView = getWrapped().restoreView(context, viewId);
} else {
loggingService.info(this, "JSF: restoreView: the cachedView instance is not null. Returning the cached view.");
}
session.setAttribute(_PREVIOUS_REQUEST_URI, currentRequestURI);
loggingService.info(this, "JSF: restoreView: end");
return cachedView;
} catch (Exception e) {
loggingService.error(this, "JSF restoreView exception", e);
throw new RuntimeException(e);
}
}
public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException {
try {
loggingService.info(this, "JSF: renderView: start");
HttpSession session = (HttpSession) context.getCurrentInstance().getExternalContext().getSession(true);
HttpServletRequest request = (HttpServletRequest) context.getCurrentInstance().getExternalContext().getRequest();
String viewName = (String) request.getAttribute(_USER_CURRENT_VIEW_ID);
if (viewName != null) {
session.setAttribute(viewName, viewToRender);
}
loggingService.info(this, "JSF: renderView: caching the UIViewRoot");
getWrapped().renderView(context, viewToRender);
loggingService.info(this, "JSF: renderView: end");
} catch (IOException ioException) {
loggingService.error(this, "JSF renderView exception", ioException);
throw ioException;
} catch (FacesException facesException) {
loggingService.error(this, "JSF renderView exception", facesException);
throw facesException;
} catch (Exception e) {
loggingService.error(this, "JSF renderView exception", e);
throw new RuntimeException(e);
}
}
@Override
public ViewHandler getWrapped() {
return this.wrapped;
}
/**
* Every time a menu navigation is performed, this method is called. From TemplateManagedBean#gotoPage().
* This is to reset the cached UIViewRoot Instance
* @param context
*/
public static void resetCachedView(FacesContext context){
loggingService.info(CustomViewHandler.class, "JSF: resetCachedView: start");
HttpSession session = (HttpSession) context.getCurrentInstance().getExternalContext().getSession(true);
Enumeration<String> sessionAttributeNames = session.getAttributeNames();
if(sessionAttributeNames!=null){
while(sessionAttributeNames.hasMoreElements()){
String sessionAttributeName = sessionAttributeNames.nextElement();
if(session.getAttribute(sessionAttributeName) instanceof UIViewRoot){
session.removeAttribute(sessionAttributeName);
loggingService.info(CustomViewHandler.class, "JSF: resetCachedView: removing cached view root :"+sessionAttributeName);
}
}
}
loggingService.info(CustomViewHandler.class, "JSF: resetCachedView: end");
}
}