用户界面线程 Flow
开发人员经常使用服务器推送来从后台任务更新用户界面(参见Background Jobs - UI Interaction)。但在 Vaadin Flow 中,有时也需要为用户界面本身启动一个单独的线程。例如,您可能希望实时显示服务器的日期和时间。
如果您熟悉 Swing,可能会倾向于使用 Timer,或者手动启动一个新 Thread。在 Flow 中,这并不是一个好的方法。Flow 应用是多用户应用,可能存在成千上万个并发用户。如果每个用户都创建自己的 Timer 或 启动自己的 Thread,线程可能会耗尽。如果发生这种情况,应用会崩溃。
更好的方案是使用虚拟线程,或使用 Spring 的 TaskExecutor 和 TaskScheduler。以下各节将介绍这些内容,并提供一些示例。
|
Note
| 本页的示例仅在启用了服务器推送的情况下有效。关于如何启用服务器推送的信息,请参阅服务器推送 文档页面。 |
虚拟线程
如果您使用支持虚拟线程的 Java 版本,则可以在需要时启动新的虚拟线程。
以下是一个按钮点击监听器的示例,用于启动一个新的虚拟线程:
Source code
Java
button.addClickListener(clickEvent -> {
Thread.ofVirtual().start(UI.getCurrent().accessLater(() -> {
// 在此处执行 UI 操作。
}, null));
});这是启动新用户界面线程的最简单方式。如果您能够使用虚拟线程,应将其作为首选方案。但如果您遇到问题,请改用 TaskExecutor。
对于计划执行的任务,您仍应使用 TaskScheduler。这将在本页面稍后的内容中介绍。
Task Executor
您还可以使用 Spring 的 TaskExecutor 和 TaskScheduler 来直接从用户界面启动任务。有关它们的配置请参阅 Background Jobs 文档页面。
在使用 TaskExecutor 和 TaskScheduler 启动任务之前,应确保这些任务确实与 UI 操作相关,而非后台任务。要正确使用它们,应当将它们注入到您的视图中,并在需要时调用。
以下示例展示了一个将 TaskExecutor 作为构造函数参数注入的视图:
Source code
Java
@Route
public class MyView extends VerticalLayout {
private final TaskExecutor taskExecutor;
public MyView(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
...
}
}此示例通过按钮点击监听器在后台线程中启动了一个 UI 操作:
Source code
Java
button.addClickListener(clickEvent -> {
taskExecutor.execute(UI.getCurrent().accessLater(() -> {
// 在此处执行 UI 操作。
}, null));
});由于调用了 UI.accessLater(),在任务完成后,用户界面会通过服务器推送进行更新。
|
Caution
|
不要在 Flow 的视图中使用 @Async 注解。这会导致视图变成代理类,而代理类在 Vaadin 中无法正常工作。
|
Task Scheduler
您可以使用 TaskScheduler 来调度任务。在使用时,您需要在组件附着(attached)时安排任务,并在组件分离(detached)时取消它。
下面的示例将每秒执行一次任务。任务将 currentTimeLabel 的文本设置为服务器当前的日期和时间。当组件被分离时,任务将被取消:
Source code
Java
@Override
protected void onAttach(AttachEvent attachEvent) {
var task = taskScheduler.scheduleAtFixedRate(
attachEvent.getUI().accessLater(() -> {
currentTimeLabel.setText(Instant.now().toString());
}, null), Duration.ofSeconds(1)
);
addDetachListener(detachEvent -> {
detachEvent.unregisterListener();
task.cancel(true);
});
}您在 Task Scheduler 中执行的任务应当执行迅速。如果您需要计划执行耗时较长的任务,应将其交给 TaskExecutor 来执行。
|
Caution
|
切勿在 Flow 的视图中使用 @Scheduled 注解。这会导致视图变成代理类,而代理类在 Vaadin 中无法正常工作。
|