解析EL值表达式的性能

FRo*_*owe 9 performance jsf el jsf-2

我有一个JSF2应用程序,它呈现一个包含复杂内容的大表.不幸的是,每个请求最多需要6秒钟来处理.在阶段监听器中使用简单的调试输出,我可以看到性能损失在处理组件树的所有阶段上均匀分布.所以我启动了一个分析器来查看详细情况,发现在一个简单的请求中评估了超过300.000个ValueExpressions.

他们解决了没有任何逻辑的非常简单的getter,所以问题不是执行这些表达式背后的代码,而是解析表达式字符串并调用getter方法.这导致了一些问题:

1.)有没有办法加快方法表达式的解析.也许隐藏的"启用缓存"标志或其他东西.

2.)似乎大多数表达式不是在渲染响应阶段内进行评估,实际需要它们,但在其他阶段.例如,styleClass在渲染阶段之外的任何其他阶段中,似乎没有必要解决.我可以阻止这个吗?

3.)当然,最小化facelets页面中EL表达式的数量应该有助于获得更多性能,但似乎我不能真正做到这一点:许多属性(如styleClass上面提到的例子)实际上依赖于表行,但是只能在列上设置.因此,有10列,每个表达式都经常被评估.我已经看到了一些示例,其中rowClasses表的属性用于有条件地设置行的样式,但由于表是可排序的,如果不滚动我自己的排序机制,这将无法工作.有没有更好的方法来实现这个?

4.)一个更简单的问题:是否有一种方法可以在组件树中缓存变量(就像ui:repeat提供对列表内容的访问并解析表达式只获取列表一次,但只是一个变量)?

非常感谢您的所有答案和提示!

编辑:

经过进一步调查,我发现每个rendered=#{someExpression}表达式在渲染响应阶段每行评估6次.我知道JSF可能不止一次地调用我的getter,但我认为这是因为它们可以在每个阶段调用.在渲染过程中,这些值不应该改变,所以我猜它们可以被缓存.

单步执行调试器中的代码,它看起来javax.faces.component.ComponentStateHelper(出现在导致已计算方法调用的每个堆栈跟踪中)提供了一个映射来完成这种缓存.但是,这似乎并不像我预期的那样有效,并且总是重新评估表达式......

Bal*_*usC 2

1.) 有什么方法可以加快方法表达式的解析速度。也许是隐藏的“启用缓存”标志或其他东西。

没有人想到。

2.) 似乎大多数表达式不是在实际需要的渲染响应阶段内评估的,而是在其他阶段评估的。例如,styleClass在渲染阶段之外的任何其他阶段似乎都没有必要进行解析。我可以阻止这种情况吗?

据我所知,这应该不会发生。在渲染响应之前唯一可以/应该解决的问题是renderedrequireddisabled和。readonlyvalue

3.) 当然,最大限度地减少 Facelets 页面中 EL 表达式的数量应该有助于获得更高的性能,但似乎我无法真正做到这一点:许多属性(如上面提到的 styleClass 示例)实际上依赖于表行,但只能在列上设置。因此,由于有 10 列,每个表达式的计算次数都过于频繁。我见过一些示例,其中表的 rowClasses 属性用于有条件地设置行的样式,但由于表是可排序的,因此如果不滚动我自己的排序机制,这将无法工作。有没有更好的方法来实现这个?

您可以将样式工作交给 JS/CSS 的智能片段/组合。

4.)还有一个更简单的问题:有没有一种方法可以在组件树中缓存变量(就像 ui:repeat 提供对列表内容的访问,并解析表达式以仅获取列表一次,但仅针对一个变量) ?

使用 JSTL <c:set>。我不确定这到底会产生什么影响,但你基本上只是将问题转移到其他地方。A#{variableName}仍需要将其定位在任何范围内的成本。您还可以考虑在访问变量时显式命名范围。例如#{sessionScope.beanname},应该跳过页面和请求范围中不必要的扫描。