如何在Struts 2中访问OGNL跟踪评估? [英] How to access OGNL tracing evaluations in Struts 2?

查看:74
本文介绍了如何在Struts 2中访问OGNL跟踪评估?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人告诉我优化Web应用程序.为此,我使用 JProfiler .

我注意到大部分响应时间都花在了表示层上.尤其是当代码构建HTML代码时.

深入研究这个瓶颈,我发现代码处理了很多OGNL类/方法(将近50%的调用).

我通过删除一些不必要的OGNL语句来优化JSP代码(请参见下文以了解详细信息).我设法获得了200ms.但是,代码仍然在这个瓶颈上平均花费超过2000毫秒.总体响应时间约为3000毫秒.

OGNL文档这样说:

从OGNL 2.5.0开始,OgnlContext对象可以自动跟踪表达式的评估. (...),您可以通过OgnlContext的 lastEvaluation属性访问最后的评估.

自从我使用Struts 2.3.15.1(OGNL v3.0.6)以来,如何从JSP文件或Action类访问此属性或调用OgnlContextgetLastEvaluation?


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">&#160;</td>
                               </s:if>
                               <s:else>
                                   <td onclick="noeudPlusMoins(this);loadChild('<s:property value="childNomenUrl" />', 'divParcours<s:property value="sidArtNomenc"/>')" class="open">&#160;</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">&#160;</td> 
                               </s:if>
                               <s:else>
                                   <td onclick="noeudPlusMoins(this);loadChild('<s:property value="childNomenUrl" />', 'divParcours<s:property value="sidArtNomenc"/>')" class="closed">&#160;</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>

解决方案

看看您的JSP代码,很明显,罪魁祸首是<s:action>标记:

您在每个迭代中调用了两个操作...,这些操作基于要迭代的行数,可能会成为一个严重的问题.

我会尝试重构该部分;瓶颈的很大一部分在于解释标签,调用动作,通过拦截器堆栈等的机制.

如果您可以生成相同的输出以最大程度地减少号召性用语,则瓶颈将大大减少.

P.S:一个非常小的优化是更改s:if中布尔和字符串比较的顺序,以利用短路(布尔比较更快):
<s:if test="#noAnchor!=true && court == nomenclatureCritere">

编辑

在没有s:action的情况下效果更好,但是页面需要它们并且我不知道如何替换它们

更清楚地说,一个动作应该

  • 执行一个(或几个)逻辑动作
  • 切勿用作辅助类.

调用popupNomenExist时,您唯一的要求是调用服务器,执行某些操作并接收结果以将其注入到JSP中.

有几种方法可以接收到该结果,调用Action可能是最糟糕的(就性能而言,由于上述原因).

您可以从popupNomenExist操作的execute()方法中获取代码,然后:

  1. 将其放在您当前操作的方法中,如RomanC链接答案中所述;
  2. 将其放在辅助类的静态方法中;
  3. 在您当前的操作中对其进行预先计算,并将结果显示为字符串列表;
  4. 依此类推...

此外,我们不能说什么是在您的popupNomenExist的execute()方法中确切执行的,但是我想有可能可以对其进行重构以防止执行某些逻辑部分,每次迭代都是通用的,将它们分组并作为一种缓存在迭代之前执行.

I was told to optimize a web application. To do so I use JProfiler.

I noticed a large part of the response time is spent in the presentation layer. Especially, when the code builds the HTML code.

Drilling down this bottle neck, I saw that the code deals a lot with OGNL classes/methods (nearly 50% of the calls).

I tuned the JSP code (see below for details) by removing some unnecessary OGNL statements. I managed to gain 200ms. However the code still spend more than 2000ms on average in this bottle neck. The overall response time is around 3000ms.

The OGNL documentation says this:

As of OGNL 2.5.0 the OgnlContext object can automatically tracks evaluations of expressions. (...) you can access the last evaluation through the lastEvaluation property of OgnlContext.

Since I use Struts 2.3.15.1 (OGNL v3.0.6) how can I access this property or call the getLastEvaluation of OgnlContext either from JSP file or Action class ?


JSP file

<%@ 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">&#160;</td>
                               </s:if>
                               <s:else>
                                   <td onclick="noeudPlusMoins(this);loadChild('<s:property value="childNomenUrl" />', 'divParcours<s:property value="sidArtNomenc"/>')" class="open">&#160;</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">&#160;</td> 
                               </s:if>
                               <s:else>
                                   <td onclick="noeudPlusMoins(this);loadChild('<s:property value="childNomenUrl" />', 'divParcours<s:property value="sidArtNomenc"/>')" class="closed">&#160;</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>

解决方案

Looking at your JSP code, it's evident that the culprits are the <s:action> tags:

You call two actions on each iteration... that basing on the number of rows you are iterating, may become a serious problem.

I would try refactoring that section; a big part of the bottleneck is in the mechanism to interpret the tag, call the action, pass through the Interceptor Stack, and so on.

If you can generate the same output minimizing the calls to actions, the bottleneck would decrease significantly.

P.S: a very minimal optimization is to change the order of the boolean and string comparison in your s:if, to exploit the short circuit (boolean comparison is faster):
<s:if test="#noAnchor!=true && court == nomenclatureCritere">

EDIT

It works better without s:action however the page need them and I don't know how to replace them

To be more clear, an Action should

  • perform one (or few) logical action;
  • never be used as an helper class.

When you call popupNomenExist , your only requirements is to call the server, do something, and receive the result to inject it in the JSP.

There are several ways to receive that result, and calling an Action is probably the worst (in terms of performances, because of the reasons listed above).

You can take the code from the execute() method of your popupNomenExist Action, and :

  1. place it in a method of YOUR current action, like described in RomanC linked answer;
  2. place it in a static method of an helper class;
  3. precalculate it in your current action, and expose the results as List of Strings;
  4. and so on...

In addition, we can't argue what is exactly being performed inside your popupNomenExist's execute() method, but I guess there are chance that it could be refactored to prevent executing some part of logic that is common to each iteration, grouping them and executing before the iteration as a sort of cache.

这篇关于如何在Struts 2中访问OGNL跟踪评估?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆