【问题标题】:How to use Future<V> correctly?如何正确使用 Future<V>?
【发布时间】:2013-08-28 22:05:20
【问题描述】:

以下代码来自支持 bean。 async()&lt;f:event listener="#{nextBean.async}" type="preRenderView"/&gt; 从视图中调用。由于我不希望此操作延迟视图的呈现,因此它会触发 EJB 中的 @Asynchronous-annotated 方法返回 Future&lt;Boolean&gt;
只要此操作正在运行,我就希望 UI 被阻止,因此我执行 &lt;p:remoteCommand&gt; 触发 ready() 来检查 Future-Object 是否有结果,这意味着异步方法已完成,然后解除对 UI 的阻止.
问题:ready() 似乎第二次调用了异步方法。我怎样才能实现我想要做的事情?

支持 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;
        }
    }

}

更新:
1. 用户被定向到外部页面的视图(作为支付过程的一部分)。
2. 请求视图的业务逻辑应该被执行,它不应该延迟视图的呈现,而是在业务逻辑执行时阻塞它的 UI。

【问题讨论】:

    标签: jakarta-ee jsf-2 primefaces


    【解决方案1】:

    抱歉,这种方法没有任何意义。

    1. 每个 HTTP 请求都会触发 preRenderView 事件。

      • 第一次打开页面算作一个 HTTP 请求。
      • &lt;p:remoteCommand autoRun="true"&gt; 算作一个 HTTP 请求。

      因此,实际上,当您打开此页面时,会触发 2 个 HTTP 请求。这就解释了为什么会调用两次preRenderView 侦听器方法。

    2. @Asynchronous 在这种情况下完全没用。您在调用@Asynchronous 方法的同一线程中调用Future#get()。在通话和Future#get() 之间,您没有做任何有用的事情。基本上,您正在阻塞当前线程并告诉它等到另一个线程完成。当前线程基本无所事事,不能用于其他任务,这是一个很大的浪费。这有什么意义?为什么不通过删除@Asynchronous 在当前线程中完成这项工作?

    您没有说明您认为 this 将是解决方案的具体功能要求,因此很难给出合适的答案或将您推向正确的方向。我猜你需要push

    【讨论】:

    • 感谢您的回答。我更新了我的问题,并希望这使功能要求更加清晰。 :)
    • 我删除了&lt;f:metadata&gt;&lt;f:event&gt; 并在正文中添加了一个简单的#{nextBean.async()},看来我得到了想要的结果。
    • 可以。请注意,这仍然是同步的。那么@Asynchronous 完全是多余的,只是浪费了整个线程。此外,如果该方法没有返回任何对 HTML 输出有用的信息,您可以在 bean 的 (post) 构造函数中完成这项工作。
    • 好的,我开始明白你在说什么了...谢谢! :)
    猜你喜欢
    • 2019-06-21
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 2021-02-10
    • 2019-11-08
    • 2021-06-10
    • 2020-06-12
    • 2021-01-08
    相关资源
    最近更新 更多