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

标签 jsf scope managed-bean

我有 2 个 JSF 托管 bean AB我需要过期/销毁/销毁 A 2 分钟后 B 5分钟后。我查了这个相关问题 Timing out from a bean ,但它正在过期整个 session 。我不想让整个 session 过期。

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

最佳答案

鉴于您使用的是 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;
    }

}

你看,它是 session 范围的并实现了 Map .至于范围,通过这种方式,它与特定的用户 session 相关联,而不是与整个应用程序相关联。如果您确实希望在应用程序中的所有用户 session 之间共享 bean,则改为将其设为应用程序范围。至于Map , 每当 JSF 需要找到托管 bean 时,它首先会尝试 get() .如果返回 null (即 bean 尚不存在),然后它将自动创建托管 bean 实例并执行 put() .

put() ,这就是提取和计算超时并将其存储在 map 中的问题。内get() ,您只需检查超时并返回 null指示 JSF 那个 bean 不再存在。然后 JSF 将简单地自动创建它并返回 put() , 等等。

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

关于jsf - 在时间间隔后使特定的托管 bean 实例过期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30748724/

相关文章:

javascript - Angular 指令代码更改范围,但模板显示相同的值

java - Xpages: managedBean 不断是 "losing"全局 Domino Session 对象

java - 使用参数制作handleFileupload以共享方法

jsf - 识别和解决javax.el.PropertyNotFoundException:目标不可达

java - 在 CSS 中定位 JSF 2.0 组件

java - 需要提交两次表格才能处理吗?

javascript - 变量全局范围理解问题

javascript - 谷歌地图 Api 和 JS 代码不起作用

css - p :selectOneMenu error when wrap around by "display: inline-block" on IE 8

java - 为什么我在 JSF 页面上有这个错误?