Spring Scheduling API 的 Quarkus 扩展
虽然鼓励用户使用 标准的 Quarkus 调度器,但 Quarkus 以 spring-scheduled
扩展的形式提供了一个 Spring Scheduled 的兼容层。
本指南将解释 Quarkus 应用程序如何利用大家熟知的 Spring Scheduled 注解来配置和调度任务。
先决条件
要完成本指南,您需要
-
大约 15 分钟
-
一个 IDE
-
已安装 JDK 17+ 并正确配置了
JAVA_HOME
-
Apache Maven 3.9.9
-
如果您想使用它,可以选择 Quarkus CLI
-
如果您想构建本机可执行文件(或者如果您使用本机容器构建,则为 Docker),可以选择安装 Mandrel 或 GraalVM 并进行适当的配置
-
对 Spring Web 扩展有一定的了解
解决方案
我们建议您按照以下章节中的说明,逐步创建应用程序。但是,您可以直接转到完整的示例。
克隆 Git 存储库:git clone https://github.com/quarkusio/quarkus-quickstarts.git
,或者下载一个 存档。
解决方案位于 spring-scheduled-quickstart
目录。
创建 Maven 项目
首先,我们需要一个新项目。使用以下命令创建一个新项目
对于 Windows 用户
-
如果使用 cmd,(不要使用反斜杠
\
并将所有内容放在同一行上) -
如果使用 Powershell,请将
-D
参数用双引号括起来,例如"-DprojectArtifactId=spring-scheduler-quickstart"
此命令将生成一个包含 spring-scheduled
扩展的 Maven 项目。
如果您已经配置了 Quarkus 项目,可以在项目根目录下运行以下命令将 spring-scheduled
扩展添加到您的项目中
quarkus extension add spring-scheduled
./mvnw quarkus:add-extension -Dextensions='spring-scheduled'
./gradlew addExtension --extensions='spring-scheduled'
这会将以下内容添加到您的构建文件中
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-scheduled</artifactId>
</dependency>
implementation("io.quarkus:quarkus-spring-scheduled")
创建计划任务
在 org.acme.spring.scheduler
包中,创建 CounterBean
类,内容如下
package org.acme.spring.scheduler;
import org.springframework.scheduling.annotation.Scheduled;
import java.util.concurrent.atomic.AtomicInteger;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped (1)
public class CounterBean {
private AtomicInteger counter = new AtomicInteger();
public int get() { (2)
return counter.get();
}
@Scheduled(cron="*/5 * * * * ?") (3)
void cronJob() {
counter.incrementAndGet(); (4)
System.out.println("Cron expression hardcoded");
}
@Scheduled(cron = "{cron.expr}") (5)
void cronJobWithExpressionInConfig() {
counter.incrementAndGet();
System.out.println("Cron expression configured in application.properties");
}
@Scheduled(fixedRate = 1000) (6)
void jobAtFixedRate() {
counter.incrementAndGet();
System.out.println("Fixed Rate expression");
}
@Scheduled(fixedRateString = "${fixedRate.expr}") (7)
void jobAtFixedRateInConfig() {
counter.incrementAndGet();
System.out.println("Fixed Rate expression configured in application.properties");
}
}
1 | 在 *application* 作用域中声明 bean。Spring 仅检测 bean 中的 @Scheduled 注解。 |
2 | get() 方法允许检索当前值。 |
3 | 使用 Spring 的 @Scheduled 注解和一个类 cron 表达式来指示 Quarkus 调度此方法的执行。在此示例中,我们计划每天上午 10:15 执行任务。 |
4 | 代码非常直观。每天上午 10:15,计数器会递增。 |
5 | 使用类 cron 表达式 cron.expr 定义一个任务,该表达式可在 application.properties 中配置。 |
6 | 定义一个以固定时间间隔执行的方法。时间间隔以毫秒为单位。 |
7 | 使用类 cron 表达式 fixedRate.expr 定义一个任务,该表达式可在 application.properties 中配置。 |
更新应用程序配置文件
编辑 application.properties
文件并添加 cron.expr
和 fixedRate.expr
配置
# The syntax used by Spring for cron expressions is the same as which is used by regular Quarkus scheduler.
cron.expr=*/5 * * * * ?
fixedRate.expr=1000
创建资源和测试
创建 CountResource
类,内容如下
package org.acme.spring.scheduler;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/count")
public class CountResource {
@Inject
CounterBean counter; (1)
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "count: " + counter.get(); (2)
}
}
1 | 注入 CounterBean |
2 | 返回当前的计数器值 |
我们还需要更新测试。编辑 CountResourceTest
类以匹配
package org.acme.spring.scheduler;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.containsString;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest
public class CountResourceTest {
@Test
public void testHelloEndpoint() {
given()
.when().get("/count")
.then()
.statusCode(200)
.body(containsString("count")); (1)
}
}
1 | 确保响应包含 count |
打包并运行应用程序
使用以下命令运行应用程序
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
在另一个终端中,运行 curl localhost:8080/count
来检查计数器值。几秒钟后,重新运行 curl localhost:8080/count
以验证计数器是否已递增。
观察控制台以验证是否已显示以下消息:- Cron expression hardcoded
- Cron expression configured in application.properties
- Fixed Rate expression
- Fixed Rate expression configured in application.properties
这些消息表明已触发了 @Scheduled
注解方法的执行。
与往常一样,可以使用以下命令打包应用程序
quarkus build
./mvnw install
./gradlew build
并使用 java -jar target/quarkus-app/quarkus-run.jar
执行。
您还可以使用以下命令生成原生可执行文件
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
使用属性表达式
Quarkus 支持在 application.properties
文件中使用属性表达式,因此为了外部化任务的配置,您应该将属性存储在 application.properties
文件中,并分别使用 fixedRateString
和 initialDelayString
参数。
请注意,此配置是构建时配置,属性表达式将在构建时解析。
不支持的 Spring Scheduled 功能
Quarkus 目前仅支持 Spring @Scheduled 提供的一部分功能,更多功能正在规划中。目前,fixedDelay
和 fixedDelayString
参数不受支持,换句话说,@Scheduled
方法总是独立执行。
重要的技术说明
请注意,Quarkus 中的 Spring 支持不会启动 Spring Application Context,也不会运行任何 Spring 基础架构类。Spring 类和注解仅用于读取元数据和/或用作用户代码方法的返回类型或参数类型。这对最终用户来说意味着,添加任意 Spring 库将不会有任何效果。此外,Spring 基础架构类(例如 org.springframework.beans.factory.config.BeanPostProcessor
)将不会被执行。