JSF 2.1 ViewScopedBean @PreDestroy метод не вызывается

У меня есть метод в виде Scoped Bean с @PreDestroy аннотация и еще один с @PostConstruct аннотаций.

@PostConstruct Метод правильно вызывается каждый раз, когда я перехожу на страницу, которая использует этот bean-объект области видимости.

Однако, когда я перехожу на новую страницу (которая не использует этот компонент области видимости) <h:link/>, @PreDestroy метод никогда не вызывается.

Я не говорю об изменении вручную URL-адреса или конца сеанса, просто в случае навигации.

Чего мне не хватает?

заранее спасибо

2 ответа

Решение

Это по замыслу. Он будет удален только тогда, когда действие POST приведет к переходу, который не является обратной передачей в то же представление (т. Е. Метод действия не вернулся null или же void, но достойный String, даже когда просто пусто).

<h:link> генерирует ссылку GET, которая не вызывает никакого действия POST. Поскольку невозможно надежно уведомить серверную часть с помощью (XML)HTTP-запроса, когда представление выгружено, JSF не может быть уведомлено об уничтожении bean-объекта области видимости, связанного с представлением. В этом случае bean-объект области видимости будет уничтожен только по истечении сеанса или когда превышено максимальное количество логических представлений в сеансе (по умолчанию 15), и связанный вид является первым по порядку.

Если вы действительно хотите уничтожить bean-объект вида с помощью действия navigaiton, то лучше всего сделать его POST-запросом: <h:commandLink> вместо этого и выполните перенаправление, возвращая результат навигации с ?faces-redirect=true параметр. Но это, в конце концов, не оптимизировано для SEO, поскольку боты не будут индексировать POST-ссылки.

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

Теоретически это возможно с помощью HTML DOM onbeforeunload событие, но это нестандартное событие, и поведение браузера не определено относительно того, что происходит, когда вы отправляете ajax-запрос во время этого события. Это иногда прибывает, но иногда также нет. Обновление: на практике это было реализовано в OmniFaces@ViewScoped начиная с OmniFaces 2.2 с помощью синхронного XHR, и он работает довольно хорошо в основных браузерах. Начиная с версии 2.3, он даже физически уничтожает связанное состояние просмотра на стороне сервера JSF.

Я подготовил небольшой проект NetBeans, демонстрирующий, когда JSF2.2 CDI-совместимые компоненты @ViewScoped (javax.faces.view.ViewScoped), совместимые с CDI, выпускаются для сбора мусора в различных навигационных случаях (для Mojarra 2.2.9, Glassfish4, NetBeans8.0.2, JDK1)..7), доступно для скачивания здесь. Код здесь опущен, смотрите, пожалуйста, загрузку.

Случаи навигации обрабатываются, и результаты суммированы этим изображением:

Изображение, показывающее страницу индекса с использованием bean-объекта @ViewSCoped с вариантами навигации JSF к готовой целевой странице

Чтобы отслеживать компоненты @ViewScoped, используйте VisualVM против Glassfish (или встроенный профилировщик NetBeans в мини-проекте) и отфильтруйте представление класса гистограммы кучи памяти сэмплера по имени пакета "webel.com.jsf". На следующем изображении показаны нелепые 66 экземпляров webel.com.jsf.Jsf22ViewBean после обильного эксперимента с h:link, браузерными GET-адресами URL и браузерными RETOAD GET, экземпляры которых не будут собираться мусором (который можно протестировать с помощью VisualVM Perform GC кнопка):

введите описание изображения здесь

Для сравнения: отходим от index.xhtml (который использует bean-компонент @ViewScoped один раз для простого чтения EL-переменной) до done.xhtml (который вообще не использует bean-компонент) с помощью h:commandButton и выражения метода действия или Строка действия приводит к тому, что bean-компонент @ViewScoped освобождается для сборки мусора (всегда есть одна ссылка из WeldClientProxy на bean-компонент @ViewScoped, и при перемещении назад и вперед с помощью h:commandButton WeldClientProxy перемещается от одного освобождаемого bean-компонента к следующему),

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