问题是 - 您如何衡量页面加载的时间,您使用的技术,您可以提供哪些推荐,以及您拥有哪些积极和消极的体验。
麻烦的是,即使是jsf中的轻页也可能需要10秒才能加载。这些页面不需要任何评估,渲染资源等。显而易见的答案 - 它在渲染队列中......好吧,但可能是其他东西?
似乎需要从请求开始测量时间,包括渲染,评估,数据传输时间,客户端渲染时间等。
您是否有任何良好的工作方式,工具链,工具可以在JSF页面中查看完整的页面时间?
使用Glassfish-3,JSF-2。机器有64个CPU。
答案 0 :(得分:6)
这是我刚刚制作和测试的一个简单的自定义解决方案。它提供了一些执行和渲染时间的统计信息。当然,所有信息都只来自服务器端处理。
结果示例:
Date ID request URL Phase Execution time
2013-05-16 21:10:29.781 34 http://localhost:8080/web/page.jspx RESTORE_VIEW 1 15
2013-05-16 21:10:29.796 34 http://localhost:8080/web/page.jspx RENDER_RESPONSE 6 4438
2013-05-16 21:10:39.437 35 http://localhost:8080/web/page.jspx RESTORE_VIEW 1 16
2013-05-16 21:10:39.453 35 http://localhost:8080/web/page.jspx RENDER_RESPONSE 6 3937
实施非常严格。首先,您必须在faces-config.xml
<lifecycle>
<phase-listener>com.spectotechnologies.jsf.phaselisteners.PhaseProcessesAnalyserListener</phase-listener>
</lifecycle>
这是帮助程序类,用于保存每个处理的信息:
package com.spectotechnologies.website.common.helper;
import java.util.Date;
import javax.faces.event.PhaseId;
/**
*
* @author Alexandre Lavoie
*/
public class PhaseProcess
{
private int m_nIDRequest;
private String m_sURL;
private Date m_oStart;
private Date m_oEnd;
private PhaseId m_oPhase;
public void setIdRequest(int p_nIDRequest)
{
m_nIDRequest = p_nIDRequest;
}
public int getIdRequest()
{
return m_nIDRequest;
}
public void setUrl(String p_sURL)
{
m_sURL = p_sURL;
}
public String getUrl()
{
return m_sURL;
}
public void setStart(Date p_oStart)
{
m_oStart = p_oStart;
}
public Date getStart()
{
return m_oStart;
}
public void setEnd(Date p_oEnd)
{
m_oEnd = p_oEnd;
}
public Date getEnd()
{
return m_oEnd;
}
public void setPhase(PhaseId p_oPhase)
{
m_oPhase = p_oPhase;
}
public PhaseId getPhase()
{
return m_oPhase;
}
public long getExecutionTime()
{
long lExecutionTime = -1;
if(getEnd() != null)
{
lExecutionTime = getEnd().getTime() - getStart().getTime();
}
return lExecutionTime;
}
}
以下是具有业务逻辑的类,请注意,目前统计数据只会增长并且永远不会被删除,因此可能是一个很好的更新,例如只保留最后一小时:
package com.spectotechnologies.website.common.helper;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseId;
/**
*
* @author Alexandre Lavoie
*/
public class PhaseProcesses
{
private List<PhaseProcess> m_lItems = new ArrayList();
private int m_nNextIDRequest = 0;
public static PhaseProcesses getInstance()
{
FacesContext oFaces = FacesContext.getCurrentInstance();
PhaseProcesses oPhaseProcesses = (PhaseProcesses)oFaces.getExternalContext().getSessionMap().get("sessionPhaseProcesses");
if(oPhaseProcesses == null)
{
oPhaseProcesses = new PhaseProcesses();
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("sessionPhaseProcesses",oPhaseProcesses);
}
return oPhaseProcesses;
}
public void set(int p_nIDRequest, String p_sURL, PhaseId p_oPhase, int p_nType)
{
PhaseProcess oPhaseProcess;
// Phase start
switch(p_nType)
{
case 0:
// start
oPhaseProcess = new PhaseProcess();
oPhaseProcess.setIdRequest(p_nIDRequest);
oPhaseProcess.setUrl(p_sURL);
oPhaseProcess.setPhase(p_oPhase);
oPhaseProcess.setStart(new Date());
if(m_lItems.size() > 250)
{
m_lItems.remove(0);
}
m_lItems.add(oPhaseProcess);
break;
case 1:
// end
for(int nPhase = m_lItems.size() - 1;nPhase >= 0;nPhase--)
{
if(m_lItems.get(nPhase).getIdRequest() == p_nIDRequest && m_lItems.get(nPhase).getPhase() == p_oPhase)
{
m_lItems.get(nPhase).setEnd(new Date());
break;
}
}
break;
}
}
public List<PhaseProcess> getList()
{
return m_lItems;
}
public Integer getNextIDRequest()
{
return m_nNextIDRequest++;
}
}
以下是着名的 PhaseListener ,其中跟踪了信息:
package com.spectotechnologies.jsf.phaselisteners;
import com.spectotechnologies.website.common.helper.PhaseProcesses;
import java.net.URLEncoder;
import java.util.Enumeration;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.HttpServletRequest;
/**
*
* @author Alexandre Lavoie
*/
public class PhaseProcessesAnalyserListener implements PhaseListener
{
@Override
public PhaseId getPhaseId()
{
return PhaseId.ANY_PHASE;
}
@Override
public void beforePhase(PhaseEvent p_oEvent)
{
PhaseProcesses.getInstance().set(getIDRequest(),getURL(),p_oEvent.getPhaseId(),0);
}
@Override
public void afterPhase(PhaseEvent p_oEvent)
{
PhaseProcesses.getInstance().set(getIDRequest(),getURL(),p_oEvent.getPhaseId(),1);
}
private Integer getIDRequest()
{
Integer iIDRequest = (Integer)FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("idrequest");
if(iIDRequest == null)
{
iIDRequest = PhaseProcesses.getInstance().getNextIDRequest();
FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("idrequest",iIDRequest);
}
return iIDRequest;
}
private String getURL()
{
Enumeration<String> lParameters;
String sParameter;
StringBuilder sbURL = new StringBuilder();
Object oRequest = FacesContext.getCurrentInstance().getExternalContext().getRequest();
try
{
if(oRequest instanceof HttpServletRequest)
{
sbURL.append(((HttpServletRequest)oRequest).getRequestURL().toString());
lParameters = ((HttpServletRequest)oRequest).getParameterNames();
if(lParameters.hasMoreElements())
{
if(!sbURL.toString().contains("?"))
{
sbURL.append("?");
}
else
{
sbURL.append("&");
}
}
while(lParameters.hasMoreElements())
{
sParameter = lParameters.nextElement();
sbURL.append(sParameter);
sbURL.append("=");
sbURL.append(URLEncoder.encode(((HttpServletRequest)oRequest).getParameter(sParameter),"UTF-8"));
if(lParameters.hasMoreElements())
{
sbURL.append("&");
}
}
}
}
catch(Exception e)
{
// Do nothing
}
return sbURL.toString();
}
}
最后,这是我创建的用于显示统计信息的简单页面。一个很好的改进可能是在页面处理上添加平均值,也就是每个idrequest处理时间。
Bean代码:
package com.spectotechnologies.website.common.beans;
import com.spectotechnologies.website.common.helper.PhaseProcess;
import com.spectotechnologies.website.common.helper.PhaseProcesses;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
/**
*
* @author Alexandre Lavoie
*/
@ManagedBean
@RequestScoped
public class PagesStatisticsActions
{
public List<PhaseProcess> getList()
{
return PhaseProcesses.getInstance().getList();
}
}
查看代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<f:view contentType="application/xhtml+xml">
<h:head>
<meta http-equiv="Content-Type" content="application/xhtml+xml;charset=UTF-8" />
</h:head>
<h:body>
<h:dataTable value="#{pagesStatisticsActions.list}" var="item">
<h:column>
<f:facet name="header">
Date
</f:facet>
<h:outputText value="#{item.start}">
<f:convertDateTime timeZone="America/Montreal" pattern="yyyy-MM-dd HH:mm:ss.SSS" />
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">
ID request
</f:facet>
#{item.idRequest}
</h:column>
<h:column>
<f:facet name="header">
URL
</f:facet>
#{item.url}
</h:column>
<h:column>
<f:facet name="header">
Phase
</f:facet>
#{item.phase}
</h:column>
<h:column>
<f:facet name="header">
Execution time (ms)
</f:facet>
#{item.executionTime}
</h:column>
</h:dataTable>
</h:body>
</f:view>
</html>
更新1:
答案 1 :(得分:1)
以下解决方案基于solution发布的Alexandre Lavoie,但适用于ADF Faces:
<强> PhaseProcessingTimeAnalyserListener 强>
import java.io.Serializable;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import oracle.adf.controller.v2.lifecycle.Lifecycle;
import oracle.adf.controller.v2.lifecycle.PagePhaseEvent;
import oracle.adf.controller.v2.lifecycle.PagePhaseListener;
import oracle.adf.share.ADFContext;
import com.mhis.posm.web.lifecycle.helper.PhaseProcessor;
/**
* Class PhaseProcessingTimeAnalyserListener calculates the execution time of each Phase of ADF
* @author TapasB
*/
public class PhaseProcessingTimeAnalyserListener implements PagePhaseListener, Serializable {
private static final long serialVersionUID = 6814928970314659328L;
/**
* Method beforePhase notifies the listener before the execution of a specific phase of the ADF Page Lifecycle.
* @author TapasB
* @param phaseEvent
* @see oracle.adf.controller.v2.lifecycle.PagePhaseListener#beforePhase(oracle.adf.controller.v2.lifecycle.PagePhaseEvent)
*/
@Override
public void beforePhase(PagePhaseEvent phaseEvent) {
int phaseId = phaseEvent.getPhaseId();
String phaseName = Lifecycle.getPhaseName(phaseId);
PhaseProcessor.getInstance().process(getRequestId(), getURL(), phaseId, phaseName, PhaseProcessor.PhaseType.BEGIN);
}
/**
* Method afterPhase notifies the listener after the execution of a specific phase of the ADF Page Lifecycle.
* @author TapasB
* @param phaseEvent
* @see oracle.adf.controller.v2.lifecycle.PagePhaseListener#afterPhase(oracle.adf.controller.v2.lifecycle.PagePhaseEvent)
*/
@Override
public void afterPhase(PagePhaseEvent phaseEvent) {
int phaseId = phaseEvent.getPhaseId();
String phaseName = Lifecycle.getPhaseName(phaseId);
PhaseProcessor.getInstance().process(getRequestId(), getURL(), phaseId, phaseName, PhaseProcessor.PhaseType.END);
}
/**
* Method getRequestId generates and returns an unique ID value for each Request
* @author TapasB
* @return requestId
*/
private Integer getRequestId() {
@SuppressWarnings("unchecked")
Map<String, Object> requestScope = ADFContext.getCurrent().getRequestScope();
Integer requestId = (Integer) requestScope.get("requestId");
if (requestId == null) {
requestId = PhaseProcessor.getInstance().getNextRequestId();
requestScope.put("requestId", requestId);
}
return requestId;
}
/**
* Method getURL returns the URL in which the application is requested
* @author TapasB
* @return a String URL
*/
private String getURL() {
Enumeration<String> parameterNames = null;
String parameterName = null;
StringBuilder urlBuilder = new StringBuilder();
Object request = FacesContext.getCurrentInstance().getExternalContext().getRequest();
try {
if (request instanceof HttpServletRequest) {
HttpServletRequest servletRequest = (HttpServletRequest) request;
urlBuilder.append(servletRequest.getRequestURL().toString());
parameterNames = servletRequest.getParameterNames();
if (parameterNames.hasMoreElements()) {
if (!urlBuilder.toString().contains("?")) {
urlBuilder.append("?");
} else {
urlBuilder.append("&");
}
}
while (parameterNames.hasMoreElements()) {
parameterName = parameterNames.nextElement();
urlBuilder.append(parameterName);
urlBuilder.append("=");
urlBuilder.append(URLEncoder.encode(servletRequest.getParameter(parameterName), "UTF-8"));
if (parameterNames.hasMoreElements()) {
urlBuilder.append("&");
}
}
}
} catch (Exception ex) {
}
return urlBuilder.toString();
}
}
PhaseProcessor
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import oracle.adf.share.ADFContext;
import com.edifixio.osrd.generic.log.Log;
/**
* Class PhaseProcessor processes the Phase execution time
* @author TapasB
*/
public class PhaseProcessor implements Serializable {
private static final long serialVersionUID = 6658181867505616109L;
private List<Phase> phases = new ArrayList<Phase>();
private AtomicInteger nextRequestId = new AtomicInteger(1);
/**
* Constructor PhaseProcessor is private
* @author TapasB
*/
private PhaseProcessor() {
}
/**
* Class PhaseType
* @author TapasB
*/
public static enum PhaseType {
BEGIN,
END;
}
/**
* Method getInstance returns a Session Instance of this class
* @author TapasB
* @return an PhaseProcessor instance
*/
public static PhaseProcessor getInstance() {
@SuppressWarnings("unchecked")
Map<String, Object> sessionScope = ADFContext.getCurrent().getSessionScope();
PhaseProcessor phaseProcessor = (PhaseProcessor) sessionScope.get("phases");
if (phaseProcessor == null) {
phaseProcessor = new PhaseProcessor();
sessionScope.put("phases", phaseProcessor);
}
return phaseProcessor;
}
/**
* Method process processes the {@link Phase}
* @author TapasB
* @param requestId - the unique ID for each request
* @param url - the url in which the application is requested
* @param phaseId - ADF's Phase ID
* @param phaseName - ADF's Phase Name
* @param phaseType - BEGIN or END
*/
public void process(int requestId, String url, int phaseId, String phaseName, PhaseType phaseType) {
Phase phase;
switch (phaseType) {
case BEGIN:
phase = new Phase();
phase.setRequestId(requestId);
phase.setUrl(url);
phase.setPhaseId(phaseId);
phase.setPhaseName(phaseName);
phase.setStartTime(new Date());
phases.add(phase);
Log.info(this, "The Phase: " + phase.getPhaseName(phaseId) + " begins. Requested URL: " + phase.getUrl());
break;
case END:
ListIterator<Phase> phaseIterator = phases.listIterator(phases.size());
while (phaseIterator.hasPrevious()) {
phase = phaseIterator.previous();
if (phase.getRequestId() == requestId && phase.getPhaseId() == phaseId && phase.getPhaseName().equals(phaseName)) {
phase.setEndTime(new Date());
Log.info(this, "The Phase: " + phase.getPhaseName(phaseId) + " ends with execution time: '" + (phase.getEndTime().getTime() - phase.getStartTime().getTime()) + "' millisecondes. Requested URL: " + phase.getUrl());
phaseIterator.remove();
break;
}
}
break;
}
}
/**
* Method getNextRequestId returns and increment the unique ID
* @author TapasB
* @return the ID
*/
public Integer getNextRequestId() {
return nextRequestId.getAndIncrement();
}
}
<强>阶段强>
import java.io.Serializable;
import java.util.Date;
import oracle.adf.controller.faces.lifecycle.JSFLifecycle;
/**
* Class Phase represent a phase
* @author TapasB
*/
public class Phase implements Serializable {
private static final long serialVersionUID = -461595462579265128L;
private int requestId;
private String url;
private Date startTime;
private Date endTime;
private int phaseId;
private String phaseName;
/**
* Constructor Phase is default
* @author TapasB
*/
public Phase() {
}
/**
* Method getRequestId returns requestId
* @author TapasB
* @return requestId
*/
public int getRequestId() {
return requestId;
}
/**
* Method setRequestId sets the requestId
* @author TapasB
* @param requestId the requestId to set
*/
public void setRequestId(int requestId) {
this.requestId = requestId;
}
/**
* Method getUrl returns url
* @author TapasB
* @return url
*/
public String getUrl() {
return url;
}
/**
* Method setUrl sets the url
* @author TapasB
* @param url the url to set
*/
public void setUrl(String url) {
this.url = url;
}
/**
* Method getStartTime returns startTime
* @author TapasB
* @return startTime
*/
public Date getStartTime() {
return startTime;
}
/**
* Method setStartTime sets the startTime
* @author TapasB
* @param startTime the startTime to set
*/
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
/**
* Method getEndTime returns endTime
* @author TapasB
* @return endTime
*/
public Date getEndTime() {
return endTime;
}
/**
* Method setEndTime sets the endTime
* @author TapasB
* @param endTime the endTime to set
*/
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
/**
* Method getPhaseId returns phaseId
* @author TapasB
* @return phaseId
*/
public int getPhaseId() {
return phaseId;
}
/**
* Method setPhaseId sets the phaseId
* @author TapasB
* @param phaseId the phaseId to set
*/
public void setPhaseId(int phaseId) {
this.phaseId = phaseId;
}
/**
* Method getPhaseName returns phaseName
* @author TapasB
* @return phaseName
*/
public String getPhaseName() {
return phaseName;
}
/**
* Method setPhaseName sets the phaseName
* @author TapasB
* @param phaseName the phaseName to set
*/
public void setPhaseName(String phaseName) {
this.phaseName = phaseName;
}
/**
* Method getPhaseName returns the name of the Phase
* @author TapasB
* @param phaseId
* @return the phase name
*/
public String getPhaseName(int phaseId) {
if (phaseId == JSFLifecycle.INIT_CONTEXT_ID) {
return "INIT_CONTEXT";
} else if (phaseId == JSFLifecycle.PREPARE_MODEL_ID) {
return "PREPARE_MODEL";
} else if (phaseId == JSFLifecycle.APPLY_INPUT_VALUES_ID) {
return "APPLY_INPUT_VALUES";
} else if (phaseId == JSFLifecycle.VALIDATE_INPUT_VALUES_ID) {
return "VALIDATE_INPUT_VALUES";
} else if (phaseId == JSFLifecycle.PROCESS_UPDATE_MODEL_ID) {
return "PROCESS_UPDATE_MODEL";
} else if (phaseId == JSFLifecycle.VALIDATE_MODEL_UPDATES_ID) {
return "VALIDATE_MODEL_UPDATES";
} else if (phaseId == JSFLifecycle.PROCESS_COMPONENT_EVENTS_ID) {
return "PROCESS_COMPONENT_EVENTS";
} else if (phaseId == JSFLifecycle.METADATA_COMMIT_ID) {
return "METADATA_COMMIT";
} else if (phaseId == JSFLifecycle.PREPARE_RENDER_ID) {
return "PREPARE_RENDER";
} else if (phaseId == JSFLifecycle.JSF_RESTORE_VIEW_ID) {
return "RESTORE_VIEW";
} else if (phaseId == JSFLifecycle.JSF_APPLY_REQUEST_VALUES_ID) {
return "JSF_APPLY_REQUEST_VALUES";
} else if (phaseId == JSFLifecycle.JSF_PROCESS_VALIDATIONS_ID) {
return "JSF_PROCESS_VALIDATIONS";
} else if (phaseId == JSFLifecycle.JSF_UPDATE_MODEL_VALUES_ID) {
return "JSF_UPDATE_MODEL_VALUES";
} else if (phaseId == JSFLifecycle.JSF_INVOKE_APPLICATION_ID) {
return "JSF_INVOKE_APPLICATION";
} else {
return "JSF_RENDER_RESPONSE";
}
}
}
有关详细信息,请查看here。