@PostConstruct вызывается несколько раз для bean-компонента @ConversationScoped
У меня есть bean-компонент @ConversationScoped с методом запуска, например:
@PostConstruct
public void start() {
if (conversation.isTransient()) {
conversation.begin();
log.debug("conversation.getId(): " + conversation.getId());
}
}
Моя проблема заключается в том, что каждый раз, когда страница обновляется, начинается новый диалог, новый диалог также запускается каждый раз, когда у меня есть вызов AJAX для метода в компоненте (что является моей главной проблемой).
То, что я действительно хочу, это чтобы разговор с Сэмом зависал до тех пор, пока я не вызову вручную. Что мне здесь не хватает?
6 ответов
Вы проверяли, что вызовы (AJAX) содержат параметр идентификатора разговора (cid)?
Если этого не произойдет, ожидается, что новый разговор начнется для каждого звонка.
Немного не по теме, но, надеюсь, ценно:
Я не уверен на 100%, что @PostConstruct - подходящее место для начала разговора. Я бы предпочел использовать Face-событие, как это:
<f:metadata>
<f:event type="javax.faces.event.PreRenderViewEvent"
listener="#{myBean.init}" />
</f:metadata>
и начните разговор, если вы уверены, что не находитесь в запросе обратной отправки JSF.
public void init() {
if (!FacesContext.getCurrentInstance().isPostback() && conversation.isTransient()) {
conversation.begin();
}
}
Если вы используете Seam 3, это еще проще:
<f:metadata>
<s:viewAction action="#{myBean.init}" if="#{conversation.transient}" />
</f:metadata>
Концепция встроенного в JSR-299 разговора немного нарушена. По крайней мере, для приложений JSF. Использование @PreRenderViewEvent в основном отбросило бы все преимущества этого подхода, поскольку каждый компонент @ConversationScoped сделал бы longRunning.
Вместо этого вы можете попробовать использовать Apache MyFaces CODI @ConversationScoped. CODI - это библиотека расширений CDI, которая хорошо работает как с Apache OpenWebBeans, так и с Weld. Кроме того, он также предоставляет контексты @ViewScoped, @ViewAccessScoped (тип автоматического разговора) и @WindowScoped.
Больше на: https://cwiki.apache.org/confluence/display/EXTCDI/Index
Это все в документах:
Область разговора активна:
на всех стандартных этапах жизненного цикла любого запроса JSF о лицах или не лицах.
Контекст диалога обеспечивает доступ к состоянию, связанному с конкретным диалогом. С каждым запросом JSF связан диалог. Эта связь автоматически управляется контейнером в соответствии со следующими правилами:
Любой запрос JSF имеет ровно один связанный разговор. Диалог, связанный с запросом JSF, определяется в начале фазы представления восстановления и не изменяется во время запроса.
Любой разговор находится в одном из двух состояний: переходный или длительный.
По умолчанию разговор является временным. Переходный разговор может быть помечен как длительный с помощью вызова Conversation.begin(). Продолжительный диалог может быть помечен как временный с помощью Conversation.end().
Все длительные диалоги имеют строковый уникальный идентификатор, который может быть установлен приложением, когда диалог помечен как длительный, или сгенерирован контейнером.
Если диалог, связанный с текущим запросом JSF, находится в переходном состоянии в конце запроса JSF, он уничтожается, и контекст диалога также разрушается.
Если в конце запроса JSF диалог, связанный с текущим запросом JSF, находится в состоянии длительного выполнения, он не уничтожается. Вместо этого он может распространяться на другие запросы в соответствии со следующими правилами:
Длительный контекст диалога, связанный с запросом, который отображает представление JSF, автоматически распространяется на любой запрос лиц (отправка формы JSF), который исходит от этой отображаемой страницы. Длительный контекст диалога, связанный с запросом, который приводит к перенаправлению JSF (перенаправление, полученное в результате правила навигации или JSF NavigationHandler), автоматически распространяется на результирующий запрос не для лиц и на любой другой последующий запрос на тот же URL-адрес. Это достигается с помощью параметра запроса GET с именем cid, содержащего уникальный идентификатор диалога. Длительный диалог, связанный с запросом, может распространяться на любой запрос, не связанный с лицами, посредством использования параметра запроса GET с именем cid, содержащего уникальный идентификатор диалога. В этом случае приложение должно управлять этим параметром запроса.
Когда в запрос JSF не передается диалог, запрос связывается с новым временным диалогом. Все длительные разговоры ограничиваются определенным сеансом сервлета HTTP и могут не пересекать границы сеанса. В следующих случаях распространенный длительный диалог не может быть восстановлен и повторно связан с запросом:
Когда сеанс сервлета HTTP признан недействительным, все контексты продолжительного диалога, созданные во время текущего сеанса, уничтожаются после завершения метода servlet service(). Контейнеру разрешено произвольно уничтожать любой продолжительный диалог, связанный с текущим запросом JSF, для сохранения ресурсов.
Автор: Гэвин Кинг, Пит Мьюир
ИМХО CDI разговоры разбиты по замыслу, и Стерберг указал на многообещающую альтернативу. В моем приложении у меня та же проблема, и в настоящее время я рефакторинг его в CDI + CODI 1, и он просто чувствует себя хорошо. @ConversationScoped решает все эти проблемы. При рефакторинге моего приложения я мог решить множество неприятных случаев с помощью @ViewAccessScoped. Спасибо, Струберг, за то, что указал нам на это!
Как ни странно, если вы добавите прослушиватель событий в ваш Facelet, даже если он вызывает пустой метод, действие формы сгенерированного источника будет иметь параметр 'cid' и, следовательно, вызов AJAX не создаст новый диалог. Без прослушивателя событий в 'cid' отсутствует действие в форме.
<f:metadata>
<f:event listener="#{myBean.dummy}" type="preRenderView" />
</f:metadata>
MyBean.java
public void dummy() {}