我被告知要优化网络应用程序。为此,我使用 JProfiler。
我注意到很大一部分响应时间花费在表示层。特别是当代码构建 HTML 代码时。
深入研究这个瓶颈,我发现代码涉及大量 OGNL 类/方法(接近 50% 的调用)。
我通过删除一些不必要的 OGNL 语句来调整 JSP 代码(详细信息见下文)。我设法获得了 200 毫秒。然而,代码在这个瓶颈上仍然平均花费超过 2000 毫秒。整体响应时间在3000ms左右。
OGNL 文档这样说:
的从 OGNL 2.5.0 开始,OgnlContext 对象可以自动“跟踪表达式的评估”。 (...) 您可以通过 OgnlContext 的 lastEvaluation 属性访问最后一次评估。 由于我使用 Struts 2.3.15.1 (OGNL v3.0.6),如何从 JSP 文件或 Action 类访问此属性或调用
getLastEvaluation
OgnlContext
?
JSP 文件
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix ="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<title><s:text name="domain.domain0.title"/></title>
<script type="text/javascript" src="<s:url value='/js/domain/domain0.js'/>"></script>
<script type="text/javascript" src="<s:url value='/js/core/html.js'/>"></script>
</head>
<body>
<div style="width:100%;color:green;font-weight: bold;text-align:center">
<s:text name="domain.domain0.information"/>
</div>
<div class="content selectFen">
<s:set var="noAnchor">false</s:set>
<s:iterator value="artefactList" status="numRow">
<s:if test="court == nomenclatureCritere && #noAnchor!=true">
<s:set var="noAnchor">true</s:set>
<a id="NomencAnchor" href="#NomencAnchor" style="visibility:hidden;"></a>
</s:if>
<s:set var="isOpen" value="nomenclatureCritere.startsWith(court) || ligProd != '80'"/>
<div class="parcoursNomenc">
<table onmouseover='this.style.backgroundColor="gainsboro"' onmouseout='this.style.backgroundColor=""' style="width: 100%;font-weight:bolder">
<tbody>
<tr>
<s:url var="childNomenUrl" action="ajaxPopupNomenChild" escapeAmp="false">
<s:param name="dateCritere" value="dateCritere"/>
<s:param name="sidNomenclaturePere" value="sidArtNomenc"/>
</s:url>
<s:if test="#isOpen">
<s:if test="#numRow.last">
<td onclick="noeudPlusMoins(this);loadChild('<s:property value="childNomenUrl" />', 'divParcours<s:property value="sidArtNomenc"/>')" class="open_last"> </td>
</s:if>
<s:else>
<td onclick="noeudPlusMoins(this);loadChild('<s:property value="childNomenUrl" />', 'divParcours<s:property value="sidArtNomenc"/>')" class="open"> </td>
</s:else>
</s:if>
<s:else>
<s:if test="#numRow.last">
<td onclick="noeudPlusMoins(this);loadChild('<s:property value="childNomenUrl" />', 'divParcours<s:property value="sidArtNomenc"/>')" class="closed_last"> </td>
</s:if>
<s:else>
<td onclick="noeudPlusMoins(this);loadChild('<s:property value="childNomenUrl" />', 'divParcours<s:property value="sidArtNomenc"/>')" class="closed"> </td>
</s:else>
</s:else>
<td style="vertical-align: top; width: 8.5em; padding-top: 5px;">
<s:text name="domain.domain0.label"/> <s:property value="court"/>
</td>
<td class="description">
<s:property value="description"/>
</td>
</tr>
</tbody>
</table>
<div id="divParcours<s:property value="sidArtNomenc"/>" class="<s:if test="numRow.last">subtree_last</s:if><s:else>subtree</s:else>" >
<s:if test="#isOpen">
<s:action name="popupNomenExist" executeResult="true">
<s:param name="dateCritere" value="dateCritere"/>
<s:param name="nomenclatureCritere" value="nomenclatureCritere"/>
</s:action>
<s:action name="ajaxPopupNomenChild" executeResult="true">
<s:param name="dateCritere" value="dateCritere"/>
<s:param name="sidNomenclaturePere" value="sidArtNomenc"/>
</s:action>
</s:if>
</div>
</div>
</s:iterator>
</div>
</body>
</html>
您在each迭代中调用两个操作...基于您正在迭代的行数,可能会成为一个严重的问题。
我会尝试重构该部分;瓶颈的很大一部分在于解释标签、调用操作、通过拦截器堆栈等的机制。
如果您可以生成相同的输出,最大限度地减少对操作的调用,那么瓶颈将显着减少。
P.S:一个非常小的优化是更改 s:if 中布尔值和字符串比较的顺序,以利用短路(布尔比较更快):
<s:if test="#noAnchor!=true && court == nomenclatureCritere">
编辑
没有
s:action
效果更好,但是页面需要它们,我不知道如何替换它们
更清楚地说,动作应该
执行一个(或几个)逻辑
动作popupNomenExist
有多种方法可以接收该结果,调用 Action 可能是最差的(就性能而言,由于上面列出的原因)。您可以从
execute()
popupNomenExist
方法中获取代码,并且:将其放入您当前操作的方法中,如 RomanC 链接答案中所述;
execute()
方法中执行的,但我想它有可能被重构以防止执行每次迭代、分组时通用的某些逻辑部分它们并在迭代之前作为一种缓存执行。
OgnlContext context = (OgnlContext) ActionContext.getContext().getValueStack().getContext();
context.setTraceEvaluations(true);
Evaluation evaluation = context.getLastEvaluation();
您在跟踪评估
部分链接的文档中描述了如何跟踪评估
您还可以在实例化上下文之前设置系统属性ognl.traceEvaluations