生命周期是一个任务task实例运行的全过程,也是一个被配置为task的Spring Boot应用被执行的过程(通过添加
@EnableTask
注解配置)
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也有内容显示。
我们还可以通过注解的方式去达到上面的目的,去完成我们对生命周期的监听,可以用下面三个注解:
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