Истек срок действия конкретного экземпляра управляемого компонента через интервал времени
У меня есть 2 JSF управляемых боба A
а также B
и мне нужно истечь / уничтожить / уничтожить A
через 2 минуты и B
через 5 минут. Я проверил этот связанный вопрос Время от бобов, но у него заканчивается весь сеанс. Я не хочу, чтобы закончить весь сеанс.
Как я могу достичь этого с помощью настраиваемой области?
1 ответ
Учитывая, что вы используете средство управления bean-компонентом JSF (и, следовательно, не CDI, что потребовало бы совершенно другого ответа), вы можете достичь этого с помощью @CustomScoped
, @CustomScoped
значение должно относиться к Map
реализация в более широкой, обычно существующей сфере.
Что-то вроде:
@ManagedBean
@CustomScoped("#{timeoutScope}")
public class TimeoutBean {}
Как @CustomScoped
аннотация не поддерживает передачу дополнительных аргументов, установка времени ожидания может быть выполнена только через дополнительную пользовательскую аннотацию, как показано ниже:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Timeout {
/** Minutes. */
int value();
}
@ManagedBean
@CustomScoped("#{timeoutScope}")
@Timeout(5) // Expires after 5 minutes.
public class TimeoutBean {}
Теперь вот пример того, как #{timeoutScope}
похоже, в том числе @PostConstruct
поддержка (автоматически) и @PreDestroy
поддержка (вручную):
@ManagedBean
@SessionScoped
public class TimeoutScope extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
@Override
public Object put(String name, Object bean) {
Timeout timeout = bean.getClass().getAnnotation(Timeout.class);
if (timeout == null) {
throw new IllegalArgumentException("@Timeout annotation is required on bean " + name);
}
Long endtime = System.nanoTime() + (timeout.value() * (long) 6e10);
Object[] beanAndEndtime = new Object[] { bean, endtime };
return super.put(name, beanAndEndtime);
}
@Override
public Object get(Object key) {
Object[] beanAndEndtime = (Object[]) super.get(key);
if (beanAndEndtime == null) {
return null;
}
Object bean = beanAndEndtime[0];
Long endtime = (Long) beanAndEndtime[1];
if (System.nanoTime() > endtime) {
String name = (String) key;
ScopeContext scope = new ScopeContext("timeoutScope", Collections.singletonMap(name, bean));
FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().publishEvent(context, PreDestroyCustomScopeEvent.class, scope);
return null;
}
return bean;
}
}
Вы видите, это сессия области и реализует Map
, Что касается области действия, то таким образом она привязана к конкретному сеансу пользователя, а не ко всему приложению. Если вы на самом деле хотите совместно использовать bean-компонент во всех пользовательских сеансах в приложении, сделайте вместо этого область приложения. Что касается Map
JSF всегда должен найти управляемый компонент, сначала он пытается get()
, Если он вернется null
(т.е. бин еще не существует), тогда он автоматически создаст экземпляр управляемого бина и выполнит put()
,
Внутри put()
, это вопрос извлечения и расчета времени ожидания и сохранения его на карте. Внутри get()
Вы просто проверяете таймаут и возвращаетесь null
чтобы указать JSF, что бин больше не существует. JSF просто создаст его автоматически и вернется на put()
, так далее.
Обратите внимание, что я использую System#nanoTime()
вместо System#currentTimeMillis()
так как последний привязан ко времени ОС (операционной системы), а не к аппаратному времени (и, таким образом, он чувствителен к летнему времени и контролируемым пользователем изменениям во времени).