Spring Cloud Task 的生命周期

Spring Cloud Task 的生命周期

生命周期是一个任务task实例运行的全过程,也是一个被配置为task的Spring Boot应用被执行的过程(通过添加@EnableTask注解配置)

TaskExecutionListener

TaskExecutionListener允许我们为任务生命周期中发生的特定事件注册侦听器。创建一个实现TaskExecutionListener接口的类。实现TaskExecutionListener接口的类会收到以下事件的通知

  • onTaskStartup: 在将TaskExecution存储到TaskRepository之前。

  • onTaskEnd: 在更新TaskExecution到TaskRepository并标记task的最终状态之前。

  • onTaskFailed: 在task抛出未处理异常时调用onTaskEnd方法之前。

下面我们通过代码来看看这个Spring Cloud Task 的生命周期:

package com.example;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.task.configuration.EnableTask;
import org.springframework.cloud.task.listener.TaskExecutionListener;
import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableTask
public class LifecycleApplication {


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

    @Bean
    public MyTaskExecutionListener taskExecutionListener() {
        return new MyTaskExecutionListener();
    }


    public static class MyTaskExecutionListener implements TaskExecutionListener {

        @Override
        public void onTaskStartup(TaskExecution taskExecution) {
            System.out.println("task start.." + taskExecution.toString());
        }

        @Override
        public void onTaskEnd(TaskExecution taskExecution) {
            System.out.println("task end.." + taskExecution.toString());
        }

        @Override
        public void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {
            System.out.println("task fail.." + taskExecution.toString());
        }
    }


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

    public static void main(String[] args) {
        SpringApplication.run(LifecycleApplication.class, args);
    }
}

然后我们来看看运行的结果:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v2.4.0-SNAPSHOT)

2020-07-18 19:27:03.048  INFO 17776 --- [           main] com.example.LifecycleApplication         : Starting LifecycleApplication using Java 1.8.0_92 on C with PID 17776 (C:\Users\c\Desktop\spring-cloud-task-demo\target\classes started by c in C:\Users\c\Desktop\spring-cloud-task-demo)
2020-07-18 19:27:03.050  INFO 17776 --- [           main] com.example.LifecycleApplication         : No active profile set, falling back to default profiles: default
2020-07-18 19:27:03.766 DEBUG 17776 --- [           main] o.s.c.t.c.SimpleTaskAutoConfiguration    : Using org.springframework.cloud.task.configuration.DefaultTaskConfigurer TaskConfigurer
2020-07-18 19:27:03.766 DEBUG 17776 --- [           main] o.s.c.t.c.DefaultTaskConfigurer          : No DataSource was found, using ResourcelessTransactionManager
2020-07-18 19:27:04.042 DEBUG 17776 --- [           main] o.s.c.t.r.support.SimpleTaskRepository   : Creating: TaskExecution{executionId=0, parentExecutionId=null, exitCode=null, taskName='HelloWorld', startTime=Sat Jul 18 19:27:04 GMT+08:00 2020, endTime=null, exitMessage='null', externalExecutionId='null', errorMessage='null', arguments=[]}
task start..TaskExecution{executionId=0, parentExecutionId=null, exitCode=null, taskName='HelloWorld', startTime=Sat Jul 18 19:27:04 GMT+08:00 2020, endTime=null, exitMessage='null', externalExecutionId='null', errorMessage='null', arguments=[]}
2020-07-18 19:27:04.071  INFO 17776 --- [           main] com.example.LifecycleApplication         : Started LifecycleApplication in 1.456 seconds (JVM running for 3.818)
Hello, World
task end..TaskExecution{executionId=0, parentExecutionId=null, exitCode=0, taskName='HelloWorld', startTime=Sat Jul 18 19:27:04 GMT+08:00 2020, endTime=Sat Jul 18 19:27:04 GMT+08:00 2020, exitMessage='null', externalExecutionId='null', errorMessage='null', arguments=[]}
2020-07-18 19:27:04.079 DEBUG 17776 --- [           main] o.s.c.t.r.support.SimpleTaskRepository   : Updating: TaskExecution with executionId=0 with the following {exitCode=0, endTime=Sat Jul 18 19:27:04 GMT+08:00 2020, exitMessage='null', errorMessage='null'}

Process finished with exit code 0

从运行的输出结果我们可以看出,onTaskStartup方法是在SimpleTaskRepository#createTaskExecution方法执行之后执行的。onTaskEnd方法是在SimpleTaskRepository#completeTaskExecution方法执行之前执行的,在CommandLineRunner#run方法执行之后之前的。

接下来我们来看看onTaskFailed是什么时候执行的,我们来改造一下我们的代码:

package com.example;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.task.configuration.EnableTask;
import org.springframework.cloud.task.listener.TaskExecutionListener;
import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableTask
public class LifecycleApplication {


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

    @Bean
    public MyTaskExecutionListener taskExecutionListener() {
        return new MyTaskExecutionListener();
    }


    public static class MyTaskExecutionListener implements TaskExecutionListener {

        @Override
        public void onTaskStartup(TaskExecution taskExecution) {
            System.out.println("task start.." + taskExecution.toString());
        }

        @Override
        public void onTaskEnd(TaskExecution taskExecution) {
            System.out.println("task end.." + taskExecution.toString());
        }

        @Override
        public void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {
            System.out.println("task fail.." + taskExecution.toString());
        }
    }


    public static class MyCommonLineRunner implements CommandLineRunner {
        @Override
        public void run(String... args) throws Exception {
            System.out.println("Hello, World");
            int i = 1 / 0;
        }
    }

    public static void main(String[] args) {
        SpringApplication.run(LifecycleApplication.class, args);
    }
}

然后我们来看看执行的结果:


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v2.4.0-SNAPSHOT)

2020-07-18 19:46:07.832  INFO 11108 --- [           main] com.example.LifecycleApplication         : Starting LifecycleApplication using Java 1.8.0_92 on C with PID 11108 (C:\Users\c\Desktop\spring-cloud-task-demo\target\classes started by c in C:\Users\c\Desktop\spring-cloud-task-demo)
2020-07-18 19:46:07.836  INFO 11108 --- [           main] com.example.LifecycleApplication         : No active profile set, falling back to default profiles: default
2020-07-18 19:46:08.579 DEBUG 11108 --- [           main] o.s.c.t.c.SimpleTaskAutoConfiguration    : Using org.springframework.cloud.task.configuration.DefaultTaskConfigurer TaskConfigurer
2020-07-18 19:46:08.579 DEBUG 11108 --- [           main] o.s.c.t.c.DefaultTaskConfigurer          : No DataSource was found, using ResourcelessTransactionManager
2020-07-18 19:46:08.856 DEBUG 11108 --- [           main] o.s.c.t.r.support.SimpleTaskRepository   : Creating: TaskExecution{executionId=0, parentExecutionId=null, exitCode=null, taskName='HelloWorld', startTime=Sat Jul 18 19:46:08 GMT+08:00 2020, endTime=null, exitMessage='null', externalExecutionId='null', errorMessage='null', arguments=[]}
task start..TaskExecution{executionId=0, parentExecutionId=null, exitCode=null, taskName='HelloWorld', startTime=Sat Jul 18 19:46:08 GMT+08:00 2020, endTime=null, exitMessage='null', externalExecutionId='null', errorMessage='null', arguments=[]}
2020-07-18 19:46:08.884  INFO 11108 --- [           main] com.example.LifecycleApplication         : Started LifecycleApplication in 1.508 seconds (JVM running for 3.896)
Hello, World
task fail..TaskExecution{executionId=0, parentExecutionId=null, exitCode=1, taskName='HelloWorld', startTime=Sat Jul 18 19:46:08 GMT+08:00 2020, endTime=Sat Jul 18 19:46:08 GMT+08:00 2020, exitMessage='null', externalExecutionId='null', errorMessage='java.lang.IllegalStateException: Failed to execute CommandLineRunner
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:788)
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:769)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:330)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1244)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1233)
	at com.example.LifecycleApplication.main(LifecycleApplication.java:55)
Caused by: java.lang.ArithmeticException: / by zero
	at com.example.LifecycleApplication$MyCommonLineRunner.run(LifecycleApplication.java:50)
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:785)
	... 5 more
', arguments=[]}
task end..TaskExecution{executionId=0, parentExecutionId=null, exitCode=1, taskName='HelloWorld', startTime=Sat Jul 18 19:46:08 GMT+08:00 2020, endTime=Sat Jul 18 19:46:08 GMT+08:00 2020, exitMessage='null', externalExecutionId='null', errorMessage='java.lang.IllegalStateException: Failed to execute CommandLineRunner
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:788)
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:769)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:330)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1244)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1233)
	at com.example.LifecycleApplication.main(LifecycleApplication.java:55)
Caused by: java.lang.ArithmeticException: / by zero
	at com.example.LifecycleApplication$MyCommonLineRunner.run(LifecycleApplication.java:50)
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:785)
	... 5 more
', arguments=[]}
2020-07-18 19:46:08.894 DEBUG 11108 --- [           main] o.s.c.t.r.support.SimpleTaskRepository   : Updating: TaskExecution with executionId=0 with the following {exitCode=1, endTime=Sat Jul 18 19:46:08 GMT+08:00 2020, exitMessage='null', errorMessage='java.lang.IllegalStateException: Failed to execute CommandLineRunner
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:788)
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:769)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:330)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1244)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1233)
	at com.example.LifecycleApplication.main(LifecycleApplication.java:55)
Caused by: java.lang.ArithmeticException: / by zero
	at com.example.LifecycleApplication$MyCommonLineRunner.run(LifecycleApplication.java:50)
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:785)
	... 5 more
'}
2020-07-18 19:46:08.895  INFO 11108 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-07-18 19:46:08.910 ERROR 11108 --- [           main] o.s.boot.SpringApplication               : Application run failed

java.lang.IllegalStateException: Failed to execute CommandLineRunner
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:788) [spring-boot-2.4.0-20200717.195013-207.jar:2.4.0-SNAPSHOT]
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:769) [spring-boot-2.4.0-20200717.195013-207.jar:2.4.0-SNAPSHOT]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:330) [spring-boot-2.4.0-20200717.195013-207.jar:2.4.0-SNAPSHOT]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1244) [spring-boot-2.4.0-20200717.195013-207.jar:2.4.0-SNAPSHOT]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1233) [spring-boot-2.4.0-20200717.195013-207.jar:2.4.0-SNAPSHOT]
	at com.example.LifecycleApplication.main(LifecycleApplication.java:55) [classes/:na]
Caused by: java.lang.ArithmeticException: / by zero
	at com.example.LifecycleApplication$MyCommonLineRunner.run(LifecycleApplication.java:50) ~[classes/:na]
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:785) [spring-boot-2.4.0-20200717.195013-207.jar:2.4.0-SNAPSHOT]
	... 5 common frames omitted


Process finished with exit code 1

CommandLineRunner#run方法抛出未捕获的异常时候,onTaskFailed会被执行,之后还会执行onTaskEnd方法,输出了如下内容:

task end..TaskExecution{executionId=0, parentExecutionId=null, exitCode=1, taskName='HelloWorld', startTime=Sat Jul 18 19:46:08 GMT+08:00 2020, endTime=Sat Jul 18 19:46:08 GMT+08:00 2020, exitMessage='null', externalExecutionId='null', errorMessage='java.lang.IllegalStateException: Failed to execute CommandLineRunner

可以看到当有异常抛出的时候,exitCode的值为1,而且errorMessage也有内容显示。

注解的方式

我们还可以通过注解的方式去达到上面的目的,去完成我们对生命周期的监听,可以用下面三个注解:

  • @BeforeTask
  • @AfterTask
  • @FailedTask
package com.example;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.task.configuration.EnableTask;
import org.springframework.cloud.task.listener.annotation.AfterTask;
import org.springframework.cloud.task.listener.annotation.BeforeTask;
import org.springframework.cloud.task.listener.annotation.FailedTask;
import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableTask
public class LifecycleApplication {


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

    @BeforeTask
    public void beforeTask(TaskExecution taskExecution){
        System.out.println("task start.." + taskExecution.toString());
    }


    @AfterTask
    public void afterTask(TaskExecution taskExecution){
        System.out.println("task end.." + taskExecution.toString());
    }


    @FailedTask
    public void failedTask(TaskExecution taskExecution){
        System.out.println("task fail.." + taskExecution.toString());
    }

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

    public static void main(String[] args) {
        SpringApplication.run(LifecycleApplication.class, args);
    }
}

然后我们来看看输出的结果:


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v2.4.0-SNAPSHOT)

2020-07-18 20:00:39.038  INFO 5436 --- [           main] com.example.LifecycleApplication         : Starting LifecycleApplication using Java 1.8.0_92 on C with PID 5436 (C:\Users\c\Desktop\spring-cloud-task-demo\target\classes started by c in C:\Users\c\Desktop\spring-cloud-task-demo)
2020-07-18 20:00:39.042  INFO 5436 --- [           main] com.example.LifecycleApplication         : No active profile set, falling back to default profiles: default
2020-07-18 20:00:39.871 DEBUG 5436 --- [           main] o.s.c.t.c.SimpleTaskAutoConfiguration    : Using org.springframework.cloud.task.configuration.DefaultTaskConfigurer TaskConfigurer
2020-07-18 20:00:39.871 DEBUG 5436 --- [           main] o.s.c.t.c.DefaultTaskConfigurer          : No DataSource was found, using ResourcelessTransactionManager
2020-07-18 20:00:40.146 DEBUG 5436 --- [           main] o.s.c.t.r.support.SimpleTaskRepository   : Creating: TaskExecution{executionId=0, parentExecutionId=null, exitCode=null, taskName='HelloWorld', startTime=Sat Jul 18 20:00:40 GMT+08:00 2020, endTime=null, exitMessage='null', externalExecutionId='null', errorMessage='null', arguments=[]}
task start..TaskExecution{executionId=0, parentExecutionId=null, exitCode=null, taskName='HelloWorld', startTime=Sat Jul 18 20:00:40 GMT+08:00 2020, endTime=null, exitMessage='null', externalExecutionId='null', errorMessage='null', arguments=[]}
2020-07-18 20:00:40.175  INFO 5436 --- [           main] com.example.LifecycleApplication         : Started LifecycleApplication in 1.631 seconds (JVM running for 4.403)
Hello, World
task end..TaskExecution{executionId=0, parentExecutionId=null, exitCode=0, taskName='HelloWorld', startTime=Sat Jul 18 20:00:40 GMT+08:00 2020, endTime=Sat Jul 18 20:00:40 GMT+08:00 2020, exitMessage='null', externalExecutionId='null', errorMessage='null', arguments=[]}
2020-07-18 20:00:40.184 DEBUG 5436 --- [           main] o.s.c.t.r.support.SimpleTaskRepository   : Updating: TaskExecution with executionId=0 with the following {exitCode=0, endTime=Sat Jul 18 20:00:40 GMT+08:00 2020, exitMessage='null', errorMessage='null'}

Process finished with exit code 0

参考

[Spring Cloud Task]2 生命周期特性与任务仓库数据结构

Spring Cloud Task 官方文档

源代码

https://gitee.com/cckevincyh/Spring-Cloud-Task/tree/lifecycle

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud TaskSpring Cloud 生态系统中的一个分布式任务调度框架,可以用于定时任务、批量处理任务等场景。下面介绍一下 Spring Cloud Task 的使用流程: 1. 添加依赖:在项目的 pom.xml 文件中添加 Spring Cloud Task 的依赖。 ``` <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-task</artifactId> </dependency> ``` 2. 配置任务:创建一个任务类,使用 @EnableTask 注解启用任务,使用 @Scheduled 注解定义任务执行的时间和频率。 ``` @EnableTask @SpringBootApplication public class MyTask { @Scheduled(fixedRate = 5000) public void myTask() { System.out.println("My task is running..."); } public static void main(String[] args) { SpringApplication.run(MyTask.class, args); } } ``` 3. 配置数据库:使用 Spring Cloud Task 需要配置一个数据库来存储任务信息和执行记录,可以使用 MySQL、PostgreSQL 等数据库。在配置文件中添加数据库连接信息。 ``` spring.datasource.url=jdbc:mysql://localhost:3306/mytask?useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.jdbc.Driver ``` 4. 运行任务:使用命令行或者 Web 界面来启动和管理任务。在命令行中执行以下命令启动任务: ``` java -jar mytask.jar --spring.cloud.task.closecontextEnabled=false ``` 5. 监控任务:Spring Cloud Task 提供了多种监控任务的方式,可以通过 Actuator、Spring Batch 等方式来监控任务的执行情况。 以上是 Spring Cloud Task 的简单使用流程,需要注意的是,在使用过程中需要考虑任务的并发、任务的失败处理、任务的日志记录等问题,需要有一定的技术储备和实践经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值