在时间间隔后使特定的托管bean实例过期

时间:2015-06-10 06:32:21

标签: jsf scope managed-bean

我有2个JSF托管bean AB,我需要在2分钟后到期/销毁/销毁A,并在5分钟后B。我检查了这个相关的问题Timing out from a bean,但是整个会话都到期了。我不想让整个会话到期。

如何使用自定义范围实现此目标?

1 个答案:

答案 0 :(得分:6)

鉴于您正在使用JSF bean管理工具(因此不需要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需要找到托管bean时,它首先尝试get()。如果它返回null(即bean尚不存在),那么它将自动创建托管bean实例并执行put()

put()内,提取和计算超时并将其存储在地图中。在get()内,您只需检查超时并返回null以指示JSF该Bean不再存在。然后,JSF将自动创建它并返回put()等等。

请注意我使用System#nanoTime()而不是System#currentTimeMillis(),因为后者与操作系统(操作系统)时间相关,而不是硬件时间(因此它对于DST和最终用户敏感 - 控制时间的变化。)