Spring Cloud Task 主要是干什么的啊?跟 Quartz 和 Spring Task 有啥关系?

背景

项目开发中涉及到分布式定时任务调度,且任务处理时又涉及到了数据分片。

最先想到的任务调度框架是 Quartz 和 Spring Task ,分析它们的特点后,发现存在两个问题:

  1. Quartz 的 API 比较复杂,支持集群任务,但不支持分片:某个任务中对一批数据的处理分配给 N 台主机处理,需要定义 N 个任务,设计好每个任务处理的数据的分配策略,可以备选。
  2. Spring Task 基于 @Scheduled 的定时任务调度,不支持集群,虽然可以通过分布式锁保证任务执行时的互斥,但是不能动态感知任务异常中断的情况,直接 Pass 掉。

因为目标项目是基于 Spring Cloud 技术开发的,看到有一个 Spring Cloud Task 的组件,感觉它可能会支持分布式任务调度,就希望搞清楚它能不能解决项目问题,于是阅读了一下官方文档。

看了第一遍,不知道它是做什么的;又看了一遍文档,搜索了一些辅助资料后,有一点知道它是干什么的了;跑了一个 Hello World ,看到了数据库中的 TASK_ 表的信息,差不多理解它是干什么的了。

那么它到底是干什么的呢?跟 Quartz 和 Spring Task 有什么关系吗?本文记录初学 Spring Cloud Task 的思考过程。

Spring Cloud Task 是干什么的?

先解决 What 的问题,官方解释是这样的:

Spring Cloud Task makes it easy to create short-lived microservices. It provides capabilities that let short lived JVM processes be executed on demand in a production environment.

Spring Cloud Task 使得创建短生存期的微服务变得更容易,它提供了在生产环境中执行短生存期的 JVM 进程的能力。

那么什么是短生存期的应用呢?我理解的是相对于我们常开发的 Java Web 这类一旦启动,不希望停止的、永不宕机的应用而言的。比如,一个普通的可执行 jar ,简单、低耗时的 Java 应用,跑一会儿就结束了的,可以称为短生存期、短运行期的应用。

short-lived microservices” 短生存期的微服务,有点颠覆我们对服务的常规理解,“服务”给人的印象是持续运行的应用,而被 @EnableTask 注解赋予 Spring Cloud Task 任务的 SpringBoot 应用就成了一次性的短生存期的任务了,貌似不能再称为服务了吧?

这是我对 Spring Cloud Task 的理解,总结这两个基本概念就是:

  1. 长生命周期的任务:Java Web 应用,一旦启动,不希望其停止的应用;
  2. 短生命周期的任务:包含一个 main 函数,没有额外线程,没有线程池调度器,main 函数完成,进程结束。

再回到开题的问题:Spring Cloud Task 到底是干什么的呢?

回想一下,你测试时执行 java -jar xxx.jar ,运行一个简单的 Java 程序。每次执行完成后就没有痕迹了,除非你自己心里有一本账:xxx X 年、X 月、X 时执行了一次 XXX.jar ,程序执行结果 成功/失败

如果恰好每一次的程序执行过程都需要记录,而且每次的运行结果也需要详细记录,作为下一个处理流的输入,这个人工操作的工作量就相当繁琐了啊。所以,Spring Cloud Task 就提供了这样一种能力,充当这个短生命周期的程序运行过程的记录员。

这就是我对 Sping Cloud Task 是干什么的个人理解,感觉应该是很接近真相了的。

援引 这篇 文章的一段作为补充:

Spring Cloud Task可以在平台环境中执行短生命周期的应用,并记录这些应用的结果,经由通过消息通知的机制来集成各个tasks。通过这特性就可以实现让短生命周期的应用像长生命周期的应用一样组成微服务架构。

Hello World 跑起来

在一个 SpringBoot 应用的主类上加 @EnableTask 注解,再添加一个 Runner 实现:

@SpringBootApplication
@EnableTransactionManagement(proxyTargetClass = true)
@EnableTask
@MapperScan({"com.xxx.dao"})
public class MainApp {
    public static void main(String[] args) {
        SpringApplication.run(MainApp.class);
    }

    @Bean
    public CommandLineRunner commandLineRunner() {
        return new HelloWorldCommandLineRunner();
    }

    public static class HelloWorldCommandLineRunner implements CommandLineRunner {
        @Override
        public void run(String... strings) throws Exception {
            System.out.println("Hello, World!");
        }
    }

}

启动应用,我有三个发现:

第一点,我是在一个可用的 SpringBoot 的 Web 应用上测试的,类注解都是正常的,加上 @EnableTask 之后,启动失败了:

The bean 'XXXService' could not be injected as a 'XXXService' because it is a JDK dynamic proxy that implements:


Action:

Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching.

Disconnected from the target VM, address: '127.0.0.1:0', transport: 'socket'

Process finished with exit code 1

加上了 @EnableTransactionManagement(proxyTargetClass = true) 这个配置才能正常启动。

第二点,原本的 Java Web 应用执行完成后容器就关闭了:
在这里插入图片描述
第三点,数据库多了几张以 TASK_ 为前缀的表,其中一张 TASK_EXECUTION 表的内容记录了这个 SpringBoot 应用每次执行的信息:
在这里插入图片描述
启动、停止时间、程序退出码等信息,这里的 TASK_NAME 是 SpringBoot 工程的名称。

启示录

现在大概能理解 Spring Cloud Task 是干啥的了,允许用户将任何 SpringBoot 应用作为短周期任务来执行,并且可以对应用的执行过程进行追踪、记录。

Spring Cloud Task 默认在任务执行完成后会关闭应用容器,因为它设计的初衷就是让 SpringBoot 应用成为一个短生命期的服务的。

但它也提供了一个配置 spring.cloud.task.closecontext_enable 可以更改这一行为,默认值为 true ,但是这么一来,这个应用就又成了长生命周期的任务了哇!

文档看了一半的时候,我隐约感觉 Spring Cloud Task 跟 Quartz 和 Spring Task 这种任务调度框架没多大的干系,它的 task 的概念跟任务调度框架的任务,好像不是同一个东西。

等我整明白了之后,再写一篇后续吧,如果有 Spring Cloud Task 大神,也欢迎指点一二。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值