如何让Wicket的“AjaxLink”无状态?

时间:2012-05-14 11:38:58

标签: java wicket stateless

我正在构建一个Wicket Web应用程序,它将不得不处理大量的同时请求。我已经设置了一个测试环境和一些jmeter脚本来进行负载测试,我注意到如果我使大多数页面无状态,我可以减少应用程序的CPU和内存占用。

我已经在最大页面的onBeforeRender()方法中添加了代码,以向我显示哪些组件导致我的页面有状态。这是我检测到的代码:

@Override
protected void onBeforeRender() {    
    if (!getSession().isTemporary()) {
        visitChildren(Component.class, new IVisitor<Component>() {
            @Override
            public Object component(Component component) {
                String pageClassName = AbstractStatelessBasePage.this.getClass().getName();
                if (!component.isStateless()) {

                    String msg = pageClassName+" is stateful because of stateful component " + component.getClass().getName() + " with id " + component.getId() + ".";

                    List<IBehavior> behaviourList = component.getBehaviors();
                    for (IBehavior iBehavior : behaviourList) {
                        if (!iBehavior.getStatelessHint(component)) {
                            msg += "\n\t" + "The component has stateful behaviour: " + iBehavior.getClass().getName();
                        }
                    }
                    LOG.error(msg);
                }

                checkedPages.add(pageClassName);
                return CONTINUE_TRAVERSAL;
            }
        });
    }
}

在输出中,我看到有状态行为是由页面中某些现有组件使用的AjaxLink引起的:

ERROR - AbstractStatelessBasePage$1.component(45) | HomePage is stateful because of stateful component InfoGrid$InfoButton with id infoButton.
    The component has stateful behaviour: org.apache.wicket.ajax.markup.html.AjaxLink$1

我试图添加getStatelessHint()方法在一些地方返回“true”,但它似乎没有帮助。我还检查了AjaxLink的Wicket源代码,它的超类和一些周围的代码,但我似乎无法发现为什么AjaxLink在所有情况下都需要有状态。

就我而言,AjaxLink处于无状态页面,链接不存储状态。如何让Wicket明白这个AjaxLink可以是无状态的?

感谢您的帮助, 罗尔夫

编辑:接受的答案适用于Wicket 1.4.19。

在maven pom.xml中添加了以下内容:

<dependency>
    <groupId>com.jolira</groupId>
    <artifactId>wicket-stateless</artifactId>
    <version>1.0.8</version>
</dependency>

更改了扩展“AjaxLink”以扩展“StatelessAjaxFallbackLink”的所有组件。

不要忘记将以下内容添加到您的WicketApplication类中,它将为您节省一些故障排除时间:

@Override
protected IRequestCycleProcessor newRequestCycleProcessor() {
    return new StatelessWebRequestCycleProcessor();
}

请注意,由于某种原因,StatelessForm和其他无状态内容无法在转发器中工作(如“ListView”)。

2 个答案:

答案 0 :(得分:10)

当您向其添加Ajax行为时,该页面将变为有状态(AjaxLink使用AjaxEventBehavior)。这是因为当您单击链接时,Wicket会尝试在服务器上查找页面实例,然后在其中找到链接组件,最后执行其回调方法 - 例如的onClick()。如果不存储页面,就无法找到ajax行为实例并执行其回调方法。

您可以使用Jolira的Ajax行为和组件(https://github.com/jolira/wicket-stateless)。它们的工作方式略有不同 - 当您单击Jolira的AjaxLink时,Ajax调用会创建一个全新的页面实例,在其中找到新创建的StatelessAjaxLink,执行其回调方法,最终使用AjaxRequestTarget为Ajax响应添加组件/ javascript,丢弃新创建的页面实例(它是垃圾回收)。下一个Ajax请求对一个全新的页面实例也是如此。

有人会问“为什么Jolira的代码不在Wicket核心?” - 因为它提供了部分解决方案。例如:单击statelessAjaxLink1创建一个新页面,在其中PanelA替换为PanelB的StatelessAjaxLink的新实例上执行onClick(),并将此面板(PanelB)添加到AjaxRequestTarget。简而言之:单击此链接将替换页面中面板的主体。如果PanelB内部有StatelessAjaxLink2,则此链接不可用。为什么?因为单击它将创建一个新的Page实例,这个新实例将具有PanelA,而不是PanelB,因此无法找到StatelessAjaxLink2来执行其onClick()方法。

如果您的场景足够简单并且Jolira的组件涵盖了您的案例,那么请使用它们。请注意,更复杂的情况可能会失败。

答案 1 :(得分:3)

wicket wiki上有一个无状态AjaxFallbackLink的代码,以及一个相关的github项目,你可以从那里获得以下链接。不确定这会完全解决你的问题,但它至少可能是有益的。

针对wicket 6尝试了类似的方法,但作者警告说它是实验性的。代码是here。我没有尝试使用它,因此无法保证它。