FacesContext.getCurrentInstance() 在 Runnable 类中返回 null

发布于 2024-09-01 08:17:23 字数 397 浏览 2 评论 0原文

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

public class Task implements Runnable {

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

}

这是如何引起的以及如何解决?

I am trying to get the FacesContext by calling FacesContext.getCurrentInstance() in the run() method of a Runnable class, but it returns null.

public class Task implements Runnable {

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

}

How is this caused and how can I solve it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

凉风有信 2024-09-08 08:17:23

FacesContext 存储为 ThreadLocal 线程中的变量负责调用 FacesServlet 的 HTTP 请求,该变量负责创建 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 示例可以在此相关问题中找到:实时使用 JSF/Java EE 从数据库进行更新。如果您碰巧使用 PrimeFaces,请查看
。如果您碰巧使用 OmniFaces,请查看 < /a>.


与具体问题无关,在 Java EE Web 应用程序中手动创建 Runnable 并手动生成线程是令人震惊的。请参阅以下问答,了解所有注意事项以及实际应该如何完成:

The FacesContext is stored as a ThreadLocal variable in the thread responsible for the HTTP request which invoked the FacesServlet, the one responsible for creating the FacesContext. This thread usually goes through the JSF managed bean methods only. The FacesContext is not available in other threads spawned by that thread.

You should actually also not have the need for it in other threads. Moreover, when your thread starts and runs independently, the underlying HTTP request will immediately continue processing the HTTP response and then disappear. You won't be able to do something with the HTTP response anyway.

You need to solve your problem differently. Ask yourself: what do you need it for? To obtain some information? Just pass that information to the Runnable during its construction instead.

The below example assumes that you'd like to access some session scoped object in the thread.

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);
// ...

If you however ultimately need to notify the client e.g. that the thread's work is finished, then you should be looking for a different solution than e.g. adding a faces message or so. The answer is to use "push". This can be achieved with SSE or websockets. A concrete websockets example can be found in this related question: Real time updates from database using JSF/Java EE. In case you happen to use PrimeFaces, look at
<p:push>. In case you happen to use OmniFaces, look at <o:socket>.


Unrelated to the concrete problem, manually creating Runnables and manually spawning threads in a Java EE web application is alarming. Head to the following Q&A to learn about all caveats and how it should actually be done:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文