🎉🎉《Spring Boot实战案例合集》目前已更新151个案例,我们将持续不断的更新。文末有电子书目录。
💪💪永久更新承诺
我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务。
💌💌如何获取
订阅我们的合集《点我订阅》,并通过私信联系我们,我们将第一时间将电子书发送给您。
环境:SpringBoot3.4.2
1. 简介
1.1 什么是JobRunr
JobRunr提供了一个统一的编程模型,以可靠的方式处理后台任务,并且可以在共享主机、专用主机或云环境(如Kubernetes)中的JVM实例上运行这些任务。
使用纯Java 8的lambda表达式,就能在Java应用程序中以令人难以置信的简便方式执行“即发即忘”(fire-and-forget)、延迟、定时和重复性任务。它支持CPU密集型、I/O密集型、长时间运行和短时间运行的任务。持久化存储可通过关系型数据库管理系统(RDBMS,如Postgres、MariaDB/MySQL、Oracle、SQL Server、DB2和SQLite)或非关系型数据库(NoSQL,如ElasticSearch、MongoDB和Redis)实现。
1.2 特性
简单:只需使用Java 8的lambda表达式即可创建后台任务
分布式且支持集群:通过乐观锁保证单个调度器实例执行任务
任务持久化:可使用关系型数据库(四张表和一个视图)或非关系型数据库存储
可嵌入:专为嵌入现有应用程序而设计
依赖项极少:(ASM、slf4j以及jackson和jackson-datatype-jsr310、gson或符合JSON-B标准的库中的任意一种)
1.3 使用场景
以下是一些可能非常适合使用JobRunr的场景:
在REST API中,立即向客户端返回响应,并在后台执行长时间运行的任务
批量通知/发送新闻通讯
计算工资并生成相应文件
从xml、csv或json批量导入数据
创建存档
触发Webhook
处理图像/视频
清除临时文件
生成定期自动化报告
数据库维护
数据变更后更新Elasticsearch/Solr
……等等
2.1 环境准备
引入依赖
<dependency><groupId>org.jobrunr</groupId><artifactId>jobrunr-spring-boot-3-starter</artifactId><version>7.5.3</version></dependency><!-- 如果你使用的Spring Boot2.x 那么请引入jobrunr-spring-boot-2-starter-->
配置
org:jobrunr:# 开启任务调度job-scheduler:enabled: true# 启用任务的后台处理background-job-server:enabled: true# 开启dashboard功能dashboard:enabled: trueusername: packpassword: 123456port: 7788
如上通过配置文件,你还可以通过代码的方式配置:
JobScheduler initJobRunr(DataSource dataSource, JobActivator jobActivator) {return JobRunr.configure().useJobActivator(jobActivator).useStorageProvider(new InMemoryStorageProvider()).useBackgroundJobServer().useDashboard().initialize().getJobScheduler();}
默认情况下,你还需要配置 StoreageProvider bean,该接口用来存储后台执行的任务信息。
StorageProvider storageProvider(JobMapper jobMapper) {InMemoryStorageProvider storageProvider = new InMemoryStorageProvider();storageProvider.setJobMapper(jobMapper) ;return storageProvider ;}
这里配置了基于内存的存储,它默认提供了非常多的实现,你可以根据自己的需要进行配置。
启动服务,访问 http://localhost:7788/dashboard
注意:用户名密码为什么配置文件中配置的,pack/123456。
2.2 手动执行任务
如下示例我们通过 @Job 定义任务,该任务将会在dashboard中展示。
public class TaskService {private final Logger logger = LoggerFactory.getLogger(getClass());public void execute() {logger.info("这是一个简单的任务, 没有任何参数") ;try {TimeUnit.SECONDS.sleep(3) ;} catch (InterruptedException e) {e.printStackTrace();} finally {logger.info("任务已完成...");}}}
接下来,我们需要通过 JobScheduler 执行任务
public class TaskController {private final JobScheduler jobScheduler;private final TaskService taskService ;public TaskController(JobScheduler jobScheduler, TaskService taskService) {this.jobScheduler = jobScheduler;this.taskService = taskService;}public ResponseEntity<?> task1() {JobId enqueue = jobScheduler.enqueue(() -> taskService.execute()) ;return ResponseEntity.ok(enqueue.toString()) ;}}
调用该接口后,我们可以从dashboard看到执行完成后的任务
对于该任务,我们还可以指定一个未来的时间执行,如下示例:
("/1")public ResponseEntity<?> task1() {JobId enqueue = jobScheduler.schedule(LocalDateTime.now().plusSeconds(30), () -> taskService.execute()) ;return ResponseEntity.ok(enqueue.toString()) ;}
指定任务30s后再执行。
2.3 自动执行任务
我们还可以通过 @Recurring 注解定义周期性的任务,如下示例:
public class TaskService {public void doRecurringJob(JobContext context) {System.out.println("周期性执行任务...") ;}}
注意:@Recurring 注解的方法只能包含零个参数,或仅包含一个类型为 org.jobrunr.jobs.context.JobContext 的参数。还有一点要注意,如果你当前的运行环境不是由 IoC 框架(如 Spring、Quarkus 或 Micronaut)管理的 Bean 中的方法,那么该注解不会生效。
上面定义的任务将会每15秒执行一次。如果我们的周期设置的小于15s,那么会每隔15s会执行(15/n次)。
启动服务后,查看dashboard
这种周期任务,我们可以在该界面进行删除或者触发任务的。管理任务是非常的方便。
2.4 任务过滤器&重试
Job 过滤器可用于在作业成功或失败时通过额外的业务流程扩展 JobRunr 的功能。
要创建作业过滤器,只需实现一个具有 JobClientFilter 或 JobServerFilter 接口的 Bean 即可。其他过滤器也可用,如 ApplyStateFilter 和 ElectStateFilter。如下示例,定义任务成功或失败的执行动作。
public class TaskFilter implements JobServerFilter {public void onProcessingSucceeded(Job job) {System.err.printf("%s - 【%s】任务成功执行完成...%n",Thread.currentThread().getName(), job.getJobName()) ;}public void onProcessingFailed(Job job, Exception e) {System.err.printf("%s - 【%s】任务执行失败,错误信息: %s%n",Thread.currentThread().getName(), job.getJobName(), e.getMessage());}}
接下来,我们为上面的任务配置过滤器
(id = "pack-job", cron = "0/15 * * * * *")(name = "Pack周期性任务", jobFilters = {TaskFilter.class})public void doRecurringJob(JobContext context) {// 这里也可以模拟异常System.out.println("周期性执行任务...") ;}
通过jobFilters可以配置多个任务过滤器。
运行结果
任务重试
当我们的任务执行失败后,可以通过配置任务重试策略,如下示例:
配置任务重试策略
org:jobrunr:jobs:default-number-of-retries: 3retry-back-off-time-seed: 1
定义带参数的任务
// 这里通过%0 可以获取第一个方法参数(name = "简单任务,有一个参数 %0")public void execute(String input) {logger.info("任务开始执行,参数input: {}", input) ;try {// 模拟错误System.err.println(1 / 0) ;} catch (Exception e) {logger.error("任务很执行错误", e);throw new RuntimeException(e) ;} finally {logger.info("任务已完成...");}}
定义Controller
("/2")public ResponseEntity<?> task2(String param) {JobId enqueue = jobScheduler.enqueue(() -> taskService.execute(param)) ;return ResponseEntity.ok(enqueue.toString()) ;}
调用任务
最终控制输出
进行了1+3次执行。
控制台查看任务最终状态
推荐文章
天呐!Java Stream 高效开发!16 个逆天案例,让你秒速起飞!
Spring Boot 结合 Redis客户端缓存技术让系统性能飙升
高级开发!一个注解动态控制Controller接口,支持实时更新
学会这3招Spring AOP切面技巧,代码解耦效率直接翻倍
如何在Spring Boot中优雅地加载配置?这些方法你必须掌握!


