Как я могу сделать Wicket "AjaxLink" без гражданства?

Я создаю веб-приложение Wicket, которое будет обрабатывать много одновременных запросов. Я настроил тестовую среду и некоторые jmeter-скрипты для нагрузочного тестирования, и я заметил, что могу уменьшить нагрузку на процессор и память моего приложения, если сделаю большинство страниц без сохранения состояния.

Я добавил код в метод 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

Я пытался добавить методы getStatelessHint(), возвращающие "true" в нескольких местах, но, похоже, это не помогает. Я также проверил исходный код Wicket для AjaxLink, его суперклассы и некоторый окружающий код, но я не могу понять, почему AjaxLink должен сохранять состояние во всех случаях.

В моем случае AjaxLink находится на другой странице без сохранения состояния, и ссылка не сохраняет состояние. Как я могу заставить Wicket понять, что этот AjaxLink может не иметь состояния?

Спасибо за вашу помощь, Рольф

Изменить: Принятый ответ работает с калиткой 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 ответа

Решение

Страница становится состоящей из состояния, когда вы добавляете к ней поведение Ajax (AjaxLink использует AjaxEventBehavior). Это происходит потому, что при нажатии на ссылку Wicket пытается найти экземпляр страницы на сервере, затем найти компонент ссылки внутри него и, наконец, выполнить свой метод обратного вызова - например, onClick(). Без сохранения страницы невозможно найти экземпляр поведения ajax и выполнить его метод обратного вызова.

Вы можете использовать поведение и компоненты Ajax от Jolira (https://github.com/jolira/wicket-stateless). Они работают немного по-другому - когда вы нажимаете на AjaxLink Джолиры, вызов Ajax создает совершенно новый экземпляр страницы, находит в нем только что созданный StatelessAjaxLink, выполняет его метод обратного вызова, в конечном итоге использует AjaxRequestTarget для добавления компонентов /javascript для ответа Ajax и сбрасывает вновь созданный экземпляр страницы (это сборщик мусора). Следующий Ajax-запрос делает то же самое с совершенно новым экземпляром страницы.

Кто-то может спросить: "Почему код Джолиры отсутствует в ядре Wicket?" - потому что это дает частичное решение. Например: нажатие на statelessAjaxLink1 создает новую страницу, выполняет onClick () для нового экземпляра StatelessAjaxLink, где PanelA заменяется PanelB, и добавляет эту панель (PanelB) в AjaxRequestTarget. Вкратце: нажатие на эту ссылку заменяет тело панели на странице. Если PanelB имеет StatelessAjaxLink2 внутри себя, эта ссылка не может быть найдена. Зачем? Поскольку щелчок по нему создаст новый экземпляр страницы, и у этого нового экземпляра будет PanelA, а не PanelB, и, следовательно, нет способа найти StatelessAjaxLink2 для выполнения его метода onClick().

Если ваш сценарий достаточно прост и компоненты Jolira покрывают ваши случаи, используйте их. Просто знайте, что более сложный сценарий может провалиться.

Есть код для лица без гражданства AjaxFallbackLink упоминается в вики wicket и связанном с ним проекте github, по которому можно перейти по следующим ссылкам. Не уверен, что это полностью решит вашу проблему, но это может быть, по крайней мере, поучительно.

Аналогичный подход был опробован для калитки 6, но автор предупреждает, что он экспериментальный. Код здесь. Я не пытался использовать это и поэтому не могу ручаться за это.

Другие вопросы по тегам