6

我试图FacesContext通过调用类FacesContext.getCurrentInstance()run()方法来获取Runnable,但它返回null.

public class Task implements Runnable {

    @Override
    public void run() {
        FacesContext context = FacesContext.getCurrentInstance(); // null!
        // ...
    }

}

这是如何引起的,我该如何解决?

4

1 回答 1

13

FacesContext作为ThreadLocal变量存储在负责调用 的 HTTP 请求的线程中,该线程负责FacesServlet创建FacesContext. 该线程通常只通过 JSF 托管 bean 方法。在该FacesContext线程产生的其他线程中不可用。

您实际上也不应该在其他线程中需要它。而且,当你的线程独立启动并运行时,底层的 HTTP 请求会立即继续处理 HTTP 响应然后消失。无论如何,您将无法对 HTTP 响应做任何事情。

你需要以不同的方式解决你的问题。问问自己:你需要它做什么?获取一些信息?只需在构建过程中将该信息传递给。Runnable

下面的示例假设您想访问线程中的某个会话范围的对象。

public class Task implements Runnable {

    private Work work;

    public Task(Work work) {
        this.work = work;
    }

    @Override
    public void run() {
        // Just use work.
    }

}
Work work = (Work) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("work");
Task task = new Task(work);
// ...

但是,如果您最终需要通知客户端,例如线程的工作已经完成,那么您应该寻找一种不同的解决方案,而不是例如添加面孔消息等。答案是使用“推”。这可以通过 SSE 或 websockets 来实现。在这个相关问题中可以找到一个具体的 websockets 示例:Real time updates from database using JSF/Java EE。如果您碰巧使用 PrimeFaces,请查看 <p:push>. 如果您碰巧使用 OmniFaces,请查看<o:socket>.


与具体问题无关,在 Java EE Web 应用程序中手动创建Runnables 和手动生成线程令人担忧。前往以下问答,了解所有注意事项以及实际应该如何完成:

于 2010-05-10T14:29:07.273 回答