8

我正在构建一个 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;
            }
        });
    }
}

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

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

我尝试在一些地方添加返回“true”的 getStatelessHint() 方法,但这似乎没有帮助。我还检查了 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”)中不起作用。

4

2 回答 2

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 会创建一个新 Page,在 PanelA 被 PanelB 替换的 StatelessAjaxLink 新实例上执行 onClick(),并将此面板 (PanelB) 添加到 AjaxRequestTarget。简而言之:单击此链接将替换页面中面板的主体。如果 PanelB 内部有一个 StatelessAjaxLink2,那么这个链接是找不到的。为什么 ?因为点击它会创建一个新的Page实例,而这个新实例会有PanelA,而不是PanelB,因此没有办法找到StatelessAjaxLink2来执行它的onClick()方法。

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

于 2012-05-14T19:26:35.877 回答
3

wicket wikiAjaxFallbackLink上引用了无状态代码,以及相关的 github 项目,您可以从那里获得以下链接。不确定这是否会完全解决您的问题,但它至少可能具有指导意义。

已经为 wicket 6 尝试了类似的方法,但作者警告说它是实验性的。代码在这里。我没有尝试使用它,因此不能保证它。

于 2012-05-14T11:56:51.797 回答