如何让Wicket的"AjaxLink"无状态?

Rol*_*olf 8 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;
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

在输出中,我看到有状态行为是由页面中某些现有组件使用的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
Run Code Online (Sandbox Code Playgroud)

我试图添加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>
Run Code Online (Sandbox Code Playgroud)

更改了扩展"AjaxLink"以扩展"StatelessAjaxFallbackLink"的所有组件.

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

@Override
protected IRequestCycleProcessor newRequestCycleProcessor() {
    return new StatelessWebRequestCycleProcessor();
}
Run Code Online (Sandbox Code Playgroud)

请注意,由于某种原因,StatelessForm和其他无状态内容在转发器(如"ListView")中不起作用.

mar*_*n-g 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的组件涵盖了您的案例,那么请使用它们.请注意,更复杂的情况可能会失败.

  • @HendyIrawan见http://central.maven.org/maven2/org/wicketstuff/wicketstuff-stateless/ (2认同)