Почему истек @ViewScoped beans не уничтожается до истечения срока действия сеанса
Я использую Mojarra 2.2.4 на GlassFish 4 с Java 7.
Как я понимаю из ответа BalusC на Как и когда @ViewScoped bean уничтожен в JSF?, @ViewScoped beans должен быть уничтожен в трех случаях
- Постобработка с нулевым результатом
- Срок действия сеанса
- Максимальное количество логических просмотров в сеансе превышено
Мой beans уничтожается в первых двух случаях, но не тогда, когда превышено максимальное количество логических просмотров. Я проверил, что beans истекает при превышении максимального значения (я получаю исключение ViewExpiredException), но они все еще не уничтожаются до истечения срока действия сеанса.
По соображениям потребления памяти я хотел бы, чтобы в этом третьем случае был уничтожен beans, тем более что они не могут использоваться после истечения срока действия.
Вопросы
- Почему beans не уничтожается, когда они истекают?
- Является ли это ошибкой или ожидаемым поведением?
- Что было бы чистой работой, чтобы убедиться, что beans будет уничтожен?
Минимальный пример
Вот мой bean:
@javax.inject.Named("sandboxController")
@javax.faces.view.ViewScoped
public class SandboxController implements Serializable {
private static final Logger log = Logger.getLogger(SandboxController.class.getName());
@PostConstruct
public void postConstruct() {
log.log(Level.INFO, "Constructing SandboxController");
}
@PreDestroy
public void preDestroy() {
log.log(Level.INFO, "Destroying SandboxController");
}
public String getData() {
return "abcdefg";
}
}
и мой sandbox.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<body>
<h:form>
<h:outputText value="#{sandboxController.data}"/>
</h:form>
</body>
</html>
и часть моего web.xml:
<context-param>
<param-name>com.sun.faces.numberOfLogicalViews</param-name>
<param-value>3</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.numberOfViewsInSession</param-name>
<param-value>3</param-value>
</context-param>
Если я обновляю sandbox.xhtml 50 раз, я получаю 50 копий INFO: Constructing SandboxController
в журнале. beans не уничтожаются, независимо от того, сколько раз я обновляю. VisualVM подтверждает, что beans по-прежнему ссылается на UIViewRoot ViewMap. В моем полноразмерном bean, который поддерживает справедливое состояние, я быстро получаю исключение OutOfMemoryException.
Когда я заканчиваю сеанс вручную, я получаю 50 копий INFO: Destroying SandboxController
.
Если я добавлю кнопку отправки в файл sandbox.xhtml и загрузим ее в 4 разных вкладки, попробуйте отправить первый, я получаю ViewExpiredException, как и ожидалось, но bean все еще не уничтожен.
Поведение такое же, если я вместо этого использую аннотации javax.faces.bean.ManagedBean и javax.faces.view.ViewScoped. Тем не менее, аннотация OmniFaces org.omnifaces.cdi.ViewScoped работает правильно.
Чтобы уточнить...
My @ViewScoped beans уничтожаются при истечении срока действия сеанса, в отличие от проблем, описанных в связанных вопросах, таких как Связанные ViewScoped beans приводят к утечкам памяти
Я не спрашиваю, почему каждый bean не сразу уничтожается при последующем обновлении, как задано здесь: JSF 2.1. Метод ViewScopedBean @PreDestroy не называется. Я хочу знать, почему это так, что даже когда они истекают и больше не полезны, они все еще не разрушаются и, следовательно, продолжают потреблять память.
Ответы
Ответ 1
Мне удалось найти чистую работу, используя аннотацию OmniFaces @ViewScoped (org.omnifaces.cdi.ViewScoped
) вместо стандартного @ViewScoped (javax.faces.view.ViewScoped
).
OmniFaces ViewScoped корректно уничтожает beans, как только они истекают.
Подробнее см. здесь:
http://showcase.omnifaces.org/cdi/ViewScoped