2013-08-28 59 views
0

下面的代碼來自一個支持bean。從<f:event listener="#{nextBean.async}" type="preRenderView"/>的視圖調用async()。由於我不希望此操作延遲視圖的呈現,因此會在EJB返回Future<Boolean>時觸發@Asynchronous -annotated方法。
只要此操作正在運行,我希望UI被阻止,因此我執行<p:remoteCommand>觸發ready(),它檢查Future -Object是否有結果,這表示異步方法已完成,然後取消阻止UI。
問題:異步方法似乎被ready()第二次調用。我怎樣才能達到我想要做的?如何正確使用Future <V>?

支持bean:

package mypackage; 

import java.util.concurrent.ExecutionException; 
import java.util.concurrent.Future; 
import javax.ejb.EJB; 
import javax.faces.bean.ManagedBean; 
import javax.faces.bean.ViewScoped; 

import lombok.Getter; 
import lombok.Setter; 
import lombok.extern.java.Log; 

@ManagedBean 
@ViewScoped 
@Getter 
@Setter 
public class NextBean { 

    @EJB private AsyncBean asyncBean; 
    private Future<Boolean> ready; 

    public void async() { 
     ready = asyncBean.async(); 
    } 

    public void ready() { 
     try { 
      while (ready.get() != true) { 
       Thread.sleep(300); 
      } 
     } catch (InterruptedException | ExecutionException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

} 

的Facelets的代碼:

<html xmlns:ui="http://java.sun.com/jsf/facelets" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:h="http://java.sun.com/jsf/html" 
     xmlns:p="http://primefaces.org/ui"> 
<h:head></h:head> 
<h:body id="wholeView"> 
    <f:metadata> 
     <f:event listener="#{nextBean.async}" type="preRenderView"></f:event> 
    </f:metadata> 
     <p:blockUI id="blockui" block=":wholeView" widgetVar="blockUI"> 
      please wait 
    </p:blockUI> 
    <h:form> 
    <p:remoteCommand onstart="blockUI.show();" 
     name="doIt" 
     id="dooo" 
     process="@this" 
     action="#{nextBean.ready}" 
     oncomplete="blockUI.hide();" 
     autoRun="true" 
    /> 

    </h:form> 
    CONTENT 
</h:body> 
</html> 

的EJB:

package mypackage; 

import java.util.concurrent.Future; 

import javax.ejb.AsyncResult; 
import javax.ejb.Asynchronous; 
import javax.ejb.Stateless; 

import lombok.extern.java.Log; 

@Stateless 
@Log 
public class AsyncBean { 

    @Asynchronous 
    public Future<Boolean> async(){ 
     try { 
      Thread.sleep(3000); 
      return new AsyncResult<Boolean>(true); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
      return null; 
     } 
    } 

} 

UPDATE:
1.用戶被引導到從外部頁面查看(如支付流程的一部分)。
2.請求視圖業務邏輯應該被執行,它不應該延遲視圖的呈現,而是在執行業務邏輯時阻止視圖的UI。

回答

2

對不起,但這種方法沒有任何意義。

  1. preRenderView事件在每個HTTP請求上被觸發。

    • 第一次打開頁面會計爲一個HTTP請求。
    • <p:remoteCommand autoRun="true">計爲一個HTTP請求。

    所以,有效的,當你只需要打開這個頁面,2個HTTP請求被解僱。這解釋了爲什麼preRenderView偵聽器方法被調用兩次。

  2. @Asynchronous在這方面完全沒用。您在調用@Asynchronous方法的同一個線程中調用Future#get()。在通話和Future#get()之間你沒有做任何有用的事情。基本上,你阻止當前線程,並告訴它等待另一個線程完成。目前的線程基本上沒有做任何事情,不能用於其他任務,這是一個主要的浪費。這有什麼意義?爲什麼不通過刪除@Asynchronous來完成當前線程中的工作?

您未說明您認爲這是解決方案的具體功能要求,因此很難給出一個合適的答案或推你在正確的方向。我想你需要push

+0

謝謝你的回答。我更新了我的問題,並希望這會使功能需求更清晰。:) – Lester

+0

我刪除了''和'',並在主體中添加了一個簡單的'#{nextBean.async()}',好像我得到了想要的結果。 – Lester

+1

可以。請注意,這仍然是同步的。那個'@ Asynchronous'然後完全是多餘的,只會浪費整個線程。另外,如果該方法沒有返回任何有用的HTML輸出用法,則可以在bean的(後)構造函數中完成這項工作。 – BalusC