4

問題は、ページの読み込み時間をどのように測定するか、どのテクニックを使用するか、どのような推奨事項を提供できるか、どのような肯定的および否定的な経験を持っているかです.

問題は、jsf の軽いページでも読み込みに最大 10 秒かかることです。これらのページは、評価やレンダリングのリソースなどを必要としません。明らかな答えは、レンダリングのキューに入っているということです...わかりました。

レンダリング、評価、データ転送時間、クライアント側のレンダリング時間など、リクエストから始まる時間を測定する必要があるようです。

JSF のページの完全な有効期間トレースのための有効な方法、ツール チェーン、ツールはありますか?

Glassfish-3、JSF-2を使用。64 個の CPU を搭載したマシン。

4

2 に答える 2

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

実装は非常に簡単です。まず、内部でPhaseListenerを構成する必要があります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;
    }
}

ビジネス ロジックを含むクラスは次のとおりです。現時点では、統計情報は増加するだけで、削除されることはありません。たとえば、最後の 1 時間だけを保持するのに適した更新になる可能性があります。

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 ごとの処理時間も追加することです。

ビーンコード:

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:

  • URL に追加されたパラメータ
  • 250 ログの制限を追加
于 2013-05-17T01:22:36.840 に答える
1

次のソリューションは、 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";
  }
 }
}

詳細については、こちらをご覧ください。

于 2014-01-01T15:33:56.040 に答える