你可以使用自定义的
ViewDeclarationLanguage
来实现这一点,该方法测量了
createView()
、
buildView()
、
renderView()
以及必要时的
restoreView()
方法。
以下是一个快速入门示例:
public class VdlLogger extends ViewDeclarationLanguageWrapper {
private static final Logger logger = Logger.getLogger(VdlLoggerFactory.class.getName());
private ViewDeclarationLanguage wrapped;
public VdlLogger(ViewDeclarationLanguage wrapped) {
this.wrapped = wrapped;
}
@Override
public UIViewRoot createView(FacesContext context, String viewId) {
long start = System.nanoTime();
UIViewRoot view = super.createView(context, viewId);
long end = System.nanoTime();
logger.info(String.format("create %s: %.6fms", viewId, (end - start) / 1e6));
return view;
}
@Override
public void buildView(FacesContext context, UIViewRoot view) throws IOException {
long start = System.nanoTime();
super.buildView(context, view);
long end = System.nanoTime();
logger.info(String.format("build %s: %.6fms", view.getViewId(), (end - start) / 1e6));
}
@Override
public void renderView(FacesContext context, UIViewRoot view) throws IOException {
long start = System.nanoTime();
super.renderView(context, view);
long end = System.nanoTime();
logger.info(String.format("render %s: %.6fms", view.getViewId(), (end - start) / 1e6));
}
@Override
public ViewDeclarationLanguage getWrapped() {
return wrapped;
}
}
为了运行它,请创建以下工厂:
public class VdlLoggerFactory extends ViewDeclarationLanguageFactory {
private ViewDeclarationLanguageFactory wrapped;
public VdlLoggerFactory(ViewDeclarationLanguageFactory wrapped) {
this.wrapped = wrapped;
}
@Override
public ViewDeclarationLanguage getViewDeclarationLanguage(String viewId) {
return new VdlLogger(wrapped.getViewDeclarationLanguage(viewId));
}
@Override
public ViewDeclarationLanguageFactory getWrapped() {
return wrapped;
}
}
请按以下方式在 faces-config.xml
中进行注册:
<factory>
<view-declaration-language-factory>com.example.VdlLoggerFactory</view-declaration-language-factory>
</factory>
createView()
是根据视图文件中的<f:view>
和<f:metadata>
创建具体的UIViewRoot
实例的步骤。在使用Facelets(XHTML)作为视图时,此步骤将通过SAX解析器解析所有关联的XHTML文件,并缓存一段时间,该时间由javax.faces.FACELETS_REFRESH_PERIOD
定义。因此,可能会有一次相对较慢,另一次快速。
buildView()
是基于视图(XHTML)组成填充JSF组件树(UIViewRoot
的getChildren()
)的步骤。在此步骤中,将执行所有标记处理程序(JSTL和朋友们),并计算那些标记处理程序和组件的id
和binding
属性中的所有EL表达式(详见JSTL in JSF2 Facelets... makes sense?)。因此,如果在视图构建期间首次构造备份bean,并在@PostConstruct
期间调用业务逻辑,则可能会发生这种耗时情况。
renderView()
是基于JSF组件树和模型生成HTML输出的步骤,从UIViewRoot#encodeAll()
开始。因此,如果在视图渲染期间首次构造备份bean,并在@PostConstruct
期间调用业务逻辑,则可能会发生这种耗时情况。
如果备份bean在getter方法中而不是在@PostConstruct
或任何其他一次性生命周期事件监听器中不正确地执行业务逻辑,则可能会发生更多时间的消耗。详见Why JSF calls getters multiple times。
ViewDeclarationLanguageWrapper
,而是应该扩展ViewDeclarationLanguage
。 源代码并不高深莫测 ;) - BalusC