我有两个JSF管理的bean,
如何使用自定义范围实现这一点?
A
和B
,我需要在2分钟后使A
过期/销毁,在5分钟后使B
过期/销毁。我查看了这个相关问题Timing out from a bean,但它会过期整个会话。我不想过期整个会话。如何使用自定义范围实现这一点?
A
和B
,我需要在2分钟后使A
过期/销毁,在5分钟后使B
过期/销毁。我查看了这个相关问题Timing out from a bean,但它会过期整个会话。我不想过期整个会话。@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需要查找托管bean时,它首先尝试get()
。如果它返回null
(即bean尚不存在),则它将自动创建托管bean实例并执行put()
。put()
内部,只需提取和计算超时时间并将其存储在映射中即可。在get()
内部,只需检查超时并返回null
以指示JSF该bean不再存在。然后JSF将简单地自动创建它,并回到put()
等等。System#nanoTime()
而不是System#currentTimeMillis()
,因为后者与操作系统时间相关,而不是与硬件时间相关(因此对夏令时和终端用户控制的时间更敏感)。@PreDestroy
吗?我实际上希望在 bean 的时间结束时立即调用 @PreDestroy
! - Junaid@PreDestroy
支持是手动的而不是自动的!它能够自动执行吗?例如,当 Bean 超时时,它会自动调用 get
或 @PreDestroy
吗?如果我在您的回答中漏掉了任何内容,请告诉我。谢谢。 - Junaid@PostConstruct
,因为JSF已经自动完成了这个任务。代码只会手动触发@PreDestroy
,因为JSF不会自动完成这个任务。publishEvent()
行就是这样做的。在提出新问题之前,请先尝试一下。 - BalusC