我正在寻找一种方法来衡量我在JSF应用程序中所有操作的执行时间。
到目前为止我发现的一个hacky解决方案是扩展 com.sun.faces.application.ActionListenerImpl ,覆盖 processAction ,并调用 super.processAction 在我的实现中:
public class MyActionListener extends ActionListenerImpl {
public void processAction(ActionEvent event) throws FacesException {
watch.start();
super.processAction(event);
watch.stop();
}
}
然后我将自己的ActionListener实现添加到faces config:
<application>
<action-listener>MyActionListener</action-listener>
</application
但是这增加了对jsf-impl的依赖性并且是hacky。有更好的解决方案吗?
答案 0 :(得分:2)
您可以改用PhaseListener
并挂钩PhaseId.INVOKE_APPLICATION
。
public class MyPhaseListener implements PhaseListener {
public PhaseId getPhaseId() {
return PhaseId.INVOKE_APPLICATION;
}
public void beforePhase(PhaseEvent event) {
watch.start();
}
public void afterPhase(PhaseEvent event) {
watch.stop();
}
}
将其注册为<phase-listener>
。
注意,我知道您的代码是伪代码,但为了完整起见,我想警告您,您需要意识到所有线程/请求之间共享同一个侦听器实例。您更愿意将watch
存储在请求映射中,而不是作为实例变量。
答案 1 :(得分:0)
最有效的解决方案是实现ServletContextListener,实现contextInitialized,为当前默认动作侦听器创建反射代理,并在代理的调用处理程序中测量时间。
@Override
public void contextInitialized(ServletContextEvent sce) {
// get JSF application factory
ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
Application application = applicationFactory.getApplication();
ActionListener defaultActionListener = application.getActionListener();
// create proxy for the default actionlistener
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
ActionListenerInvocationHandler actionListenerInvocationHandler = new ActionListenerInvocationHandler(defaultActionListener);
@SuppressWarnings("rawtypes")
Class[] interfaces = new Class[] { ActionListener.class };
ActionListener actionListenerProxy = (ActionListener) Proxy.newProxyInstance(contextClassLoader, interfaces, actionListenerInvocationHandler);
// set proxied actionListener as new default actionlistener
application.setActionListener(actionListenerProxy);
}