能否用componentCache提升JSF性能?相关实现与优化疑问
JSF组件查找性能优化及相关疑问(针对Mojarra 2.1.18)
我们发现JSF实现中,通过clientId递归迭代或visitTree方法查找组件存在明显性能瓶颈。针对Mojarra 2.1.18版本,我们制作了优化补丁:移除FaceletFullStateManagementStrategy、FaceletPartialStateManagementStrategy、FaceletViewHandlingStrategy三类中的locateComponentByClientId方法,改用带SKIP_ITERATION_HINT的全量visitTree构建<String, UIComponent>映射缓存组件,实测应用性能提升约30%。
疑问
- 为何
FaceletFullStateManagementStrategy与FaceletPartialStateManagementStrategy的组件定位逻辑完全一致,但FaceletViewHandlingStrategy的实现却差异显著? FaceletViewHandlingStrategy.locateComponentByClientId函数会在哪些场景下被调用?- Mojarra等JSF实现为何默认不通过ID缓存组件树?是否是因为clientId的动态性过强导致缓存难度大?
- 在Mojarra中实现组件缓存的最佳位置在哪里?
优化代码实现
我们通过性能测试发现大量线程阻塞在visitTree函数中,因此实现了以下组件缓存映射构建逻辑:
private static final Set<VisitHint> SKIP_ITERATION_HINT = EnumSet.of(SKIP_ITERATION); public Map<String, UIComponent> createCompCache(FacesContext context) { final Map<String, UIComponent> compCache = new HashMap<>(); try { context.getAttributes().put(SKIP_ITERATION_HINT, true); Set<VisitHint> hints = EnumSet.of(VisitHint.SKIP_ITERATION); VisitContext visitContext = VisitContext.createVisitContext(context, null, hints); context.getViewRoot().visitTree(visitContext, (visitContext1, component) -> { compCache.put(component.getClientId(visitContext.getFacesContext()), component); return VisitResult.ACCEPT; }); return compCache; } finally { context.getAttributes().remove(SKIP_ITERATION_HINT); } }
同时将原组件查找代码:
UIComponent child = locateComponentByClientId(context, parent, struct.getClientId());
替换为:
UIComponent child = compCache.get(struct.getClientId());
后续计划与请求
目前我们尚未在新版Mojarra中进行压力测试,但认为该优化方案具备有效性。我们希望将此补丁作为PR提交至Mojarra主分支,恳请JSF专家(如@BalusC)提供建议,比如是否存在更优的缓存位置、能否对invokeOnComponent方法进行类似优化等。
内容的提问来源于stack exchange,提问作者László Tóth
相关产品推荐
相关产品推荐

