2015-06-10 74 views
5

我有2個JSF託管的bean AB,我需要在5分鐘後過期/銷燬/銷燬AB。我檢查了這個相關的問題Timing out from a bean,但它正在過期整個會話。我不想過期整個會議。在時間間隔後過期特定的託管bean實例

如何使用自定義範圍實現此目的?

+0

你不能這樣做,如果容器管理你的豆 – Dummy

+0

@Dummy他們是JSF /管理bean **不** ** ejbs!我正在管理JSF beans的範圍! – Junaid

+0

你沒有明確地說過,你可以在技術上使用會話bean作爲你的jsf支持bean。如果是這樣,你是否想過計時器服務? – Dummy

回答

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()後者是依賴於OS(操作系統)的時間,而不是硬件的時間(和因此它對時間和最終用戶控制的變化敏感)。

+0

所以'@ PreDestroy'支持(自動)沒有辦法?一旦bean的時間結束,我真的想要'@ PreDestroy'調用! – Junaid

+0

也許你錯過了更新的答案,或者沒有真正嘗試或者沒有逐行閱讀代碼? – BalusC

+0

好吧,我閱讀更新後的答案和代碼!我的理解是'@ PreDestroy'支持手動** NOT **自動!它可以**自動**,就像每當Bean超時它會自動調用'get'或'@ PreDestroy'?如果我錯過了答案中的任何內容,請讓我知道。謝謝 – Junaid