An Intro to Spring Cloud Task – Spring Cloud Task介绍

最后修改: 2018年 2月 27日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

The goal of Spring Cloud Task is to provide the functionality of creating short-lived microservices for Spring Boot application.

Spring Cloud Task的目标是为Spring Boot应用提供创建短期微服务的功能

In Spring Cloud Task, we’ve got the flexibility of running any task dynamically, allocating resources on demand and retrieving the results after the Task completion.

在Spring Cloud Task中,我们可以灵活地动态运行任何任务,按需分配资源并在任务完成后检索结果。

Tasks is a new primitive within Spring Cloud Data Flow allowing users to execute virtually any Spring Boot application as a short-lived task.

任务是Spring Cloud Data Flow中的一个新基元,允许用户将几乎任何Spring Boot应用程序作为一个短暂的任务执行

2. Developing a Simple Task Application

2.开发一个简单的任务应用程序

2.1. Adding Relevant Dependencies

2.1.添加相关的依赖关系

To start, we can add dependency management section with spring-cloud-task-dependencies:

首先,我们可以用spring-cloud-task-dependencies添加依赖性管理部分:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-task-dependencies</artifactId>
            <version>2.2.3.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

This dependency management manages versions of dependencies through the import scope.

该依赖管理通过导入范围管理依赖的版本。

We need to add the following dependencies:

我们需要添加以下依赖项。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-task</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-task-core</artifactId>
</dependency>

This is the link to the Maven Central of spring-cloud-task-core.

这个是指向 spring-cloud-task-core的Maven中心的链接。

Now, to start our Spring Boot application, we need spring-boot-starter with the relevant parent.

现在,为了启动我们的Spring Boot应用程序,我们需要spring-boot-starter与相关的父级。

We’re going to use Spring Data JPA as an ORM tool, so we need to add the dependency for that as well:

我们将使用Spring Data JPA作为ORM工具,所以我们也需要添加它的依赖性。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>2.6.1</version>
</dependency>

The details of bootstrapping a simple Spring Boot application with Spring Data JPA are available here.

使用 Spring Data JPA 引导一个简单的 Spring Boot 应用程序的细节可在此处获得。

We can check the newest version of the spring-boot-starter-parent on Maven Central.

我们可以查看spring-boot-starter-parentn Maven Central的最新版本。

2.2. The @EnableTask Annotation

2.2.@EnableTask 注释

To bootstrap the functionality of Spring Cloud Task, we need to add @EnableTask annotation:

为了启动Spring Cloud Task的功能,我们需要添加@EnableTask注释。

@SpringBootApplication
@EnableTask
public class TaskDemo {
    // ...
}

The annotation brings SimpleTaskConfiguration class in the picture which in turns registers the TaskRepository and its infrastructure. By default, an in-memory map is used to store the status of the TaskRepository.

该注解将SimpleTaskConfiguration类带入图片中,该类又注册了TaskRepository及其基础设施。默认情况下,内存中的映射被用来存储TaskRepository的状态。

The primary information of TaskRepository is modeled in TaskExecution class. The noted fields of this class are taskName, startTime, endTime, exitMessage. The exitMessage stores the available information at the exit time.

TaskRepository的主要信息在TaskExecution类中建模。这个类的字段是taskNamestartTimeendTimeexitMessageexitMessage存储退出时的可用信息。

If an exit is caused by a failure in any event of the application, the complete exception stack trace will be stored here.

如果退出是由应用程序的任何事件的失败引起的,完整的异常堆栈跟踪将被存储在这里。

Spring Boot provides an interface ExitCodeExceptionMapper which maps uncaught exceptions to exit codes allowing scrutinized debug. The Cloud Task stores the information in the data source for future analysis.

Spring Boot提供了一个接口ExitCodeExceptionMapper,它将未捕获的异常映射为退出代码,允许仔细调试。云任务将信息存储在数据源中,以便将来分析。

2.3. Configuring a DataSource for TaskRepository

2.3.为TaskRepository配置DataSource

The in-memory map to store the TaskRepository will vanish once the task ends and we’ll lose data related to Task events. To store in a permanent storage, we’re going to use MySQL as a data source with Spring Data JPA.

一旦任务结束,用于存储TaskRepository的内存地图将消失,我们将失去与任务事件相关的数据。为了存储在一个永久的存储器中,我们将使用MySQL作为数据源与Spring Data JPA。

The data source is configured in application.yml file. To configure Spring Cloud Task to use the provided data source as an storage of TaskRepository, we need to create a class that extends DefaultTaskConfigurer.

数据源是在application.yml文件中配置的。为了配置Spring Cloud Task使用所提供的数据源作为TaskRepository的存储,我们需要创建一个扩展DefaultTaskConfigurer的类。

Now, we can send configured Datasource as a constructor argument to the superclass’ constructor:

现在,我们可以将配置好的Datasource作为构造函数参数发送给超类的构造函数。

@Autowired
private DataSource dataSource;

public class HelloWorldTaskConfigurer extends DefaultTaskConfigurer{
    public HelloWorldTaskConfigurer(DataSource dataSource){
        super(dataSource);
    }
}

To have the above configuration in action, we need to annotate an instance of DataSource with @Autowired annotation and inject the instance as constructor-argument of a HelloWorldTaskConfigurer bean defined above:

为了实现上述配置,我们需要用@Autowired注解来注解DataSource的一个实例,并将该实例作为上述定义的HelloWorldTaskConfigurerBean的构造参数注入。

@Bean
public HelloWorldTaskConfigurer getTaskConfigurer() {
    return new HelloWorldTaskConfigurer(dataSource);
}

This completes the configuration to store TaskRepository to MySQL database.

这就完成了将TaskRepository存储到MySQL数据库的配置。

2.4. Implementation

2.4.实施

In Spring Boot, we can execute any Task just before application finishes its startup. We can use ApplicationRunner or CommandLineRunner interfaces to create a simple Task.

在Spring Boot中,我们可以在应用程序完成启动之前执行任何任务。我们可以使用ApplicationRunnerCommandLineRunner接口来创建一个简单的任务。

We need to implement the run method of these interfaces and declare the implementing class as a bean:

我们需要实现这些接口的run方法,并将实现类声明为Bean。

@Component
public static class HelloWorldApplicationRunner 
  implements ApplicationRunner {
 
    @Override
    public void run(ApplicationArguments arg0) throws Exception {
        System.out.println("Hello World from Spring Cloud Task!");
    }
}

Now, if we run our application, we should get our task producing necessary output with required tables created in our MySQL database logging the event data of the Task.

现在,如果我们运行我们的应用程序,我们应该得到我们的任务产生必要的输出,并在我们的MySQL数据库中创建必要的表,记录任务的事件数据。

3. Life-cycle of a Spring Cloud Task

3.Spring Cloud任务的生命周期

In the beginning, we create an entry in the TaskRepository. This’s the indication that all beans are ready to be used in the Application and the run method of Runner interface is ready to be executed.

在开始时,我们在TaskRepository中创建一个条目。这表明所有的Bean已经准备好在应用程序中使用,Runner接口的run方法已经准备好被执行。

Upon completion of the execution of the run method or in any failure of ApplicationContext event, TaskRepository will be updated with another entry.

在完成run方法的执行后,或者在任何ApplicationContext事件的失败中,TaskRepository将被更新为另一个条目。

During the task life-cycle, we can register listeners available from TaskExecutionListener interface. We need a class implementing the interface having three methods – onTaskEnd, onTaksFailed and onTaskStartup triggered in respective events of the Task.

在任务的生命周期中,我们可以从TaskExecutionListener接口注册监听器。我们需要一个实现该接口的类,它有三个方法–onTaskEndonTaksFailedonTaskStartup在任务的各个事件中触发。

We need to declare the bean of the implementing class in our TaskDemo class:

我们需要在我们的TaskDemo类中声明实现类的bean。

@Bean
public TaskListener taskListener() {
    return new TaskListener();
}

4. Integration With Spring Batch

4.与Spring Batch的集成

We can execute Spring Batch Job as a Task and log events of the Job execution using Spring Cloud Task. To enable this feature we need to add Batch dependencies pertaining to Boot and Cloud:

我们可以将Spring Batch Job作为一个任务来执行,并使用Spring Cloud Task来记录Job执行的事件。要启用这个功能,我们需要添加与Boot和Cloud有关的Batch依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-task-batch</artifactId>
</dependency>

Here is the link to the Maven Central of spring-cloud-task-batch.

这里是指向spring-cloud-task-batch的Maven中心的链接。

To configure a job as a Task we need to have the Job bean registered in the JobConfiguration class:

要将一项工作配置为一个任务,我们需要在JobConfiguration类中注册Job Bean。

@Bean
public Job job2() {
    return jobBuilderFactory.get("job2")
      .start(stepBuilderFactory.get("job2step1")
      .tasklet(new Tasklet(){
          @Override
          public RepeatStatus execute(
            StepContribution contribution,
            ChunkContext chunkContext) throws Exception {
            System.out.println("This job is from Baeldung");
                return RepeatStatus.FINISHED;
          }
    }).build()).build();
}

We need to decorate the TaskDemo class with @EnableBatchProcessing annotation:

我们需要用@EnableBatchProcessing注释来装饰TaskDemo

//..Other Annotation..
@EnableBatchProcessing
public class TaskDemo {
    // ...
}

The @EnableBatchProcessing annotation enables Spring Batch features with a base configuration required to set up batch jobs.

@EnableBatchProcessing注解通过设置批处理工作所需的基本配置来启用Spring Batch功能。

Now, if we run the application, the @EnableBatchProcessing annotation will trigger the Spring Batch Job execution and Spring Cloud Task will log the events of the executions of all batch jobs with the other Task executed in the springcloud database.

现在,如果我们运行应用程序,@EnableBatchProcessing注解将触发Spring批处理作业的执行,Spring云任务将记录所有批处理作业的执行事件与springcloud数据库中执行的其他任务。

5. Launching a Task from Stream

5.从流中启动一个任务

We can trigger Tasks from Spring Cloud Stream. To serve this purpose, we have the @EnableTaskLaucnher annotation. Once, we add the annotation with Spring Boot app, a TaskSink will be available:

我们可以从Spring Cloud Stream触发任务。为了达到这个目的,我们有@EnableTaskLaucnher注解。一旦我们在Spring Boot应用程序中添加该注解,就会有一个TaskSink可用。

@SpringBootApplication
@EnableTaskLauncher
public class StreamTaskSinkApplication {
    public static void main(String[] args) {
        SpringApplication.run(TaskSinkApplication.class, args);
    }
}

The TaskSink receives the message from a stream that contains a GenericMessage containing TaskLaunchRequest as a payload. Then it triggers a Task-based on co-ordinate provided in the Task launch request.

TaskSink从一个包含GenericMessage的流中接收消息,该流包含TaskLaunchRequest作为有效载荷。然后,它根据任务启动请求中提供的坐标来触发一个任务。

To have TaskSink functional, we require a bean configured that implements TaskLauncher interface. For testing purpose, we’re mocking the implementation here:

为了让TaskSink发挥作用,我们需要配置一个实现了TaskLauncher接口的bean。出于测试的目的,我们在这里模拟了这个实现。

@Bean
public TaskLauncher taskLauncher() {
    return mock(TaskLauncher.class);
}

We need to note here that the TaskLauncher interface is only available after adding the spring-cloud-deployer-local dependency:

我们在此需要注意的是,只有在添加spring-cloud-deployer-local依赖性之后,TaskLauncher界面才可用:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-deployer-local</artifactId>
    <version>2.3.1.RELEASE</version>
</dependency>

We can test whether the Task launched by invoking input of the Sink interface:

我们可以通过调用inputSink接口来测试任务是否启动。

public class StreamTaskSinkApplicationTests {
   
    @Autowired
    private Sink sink; 
    
    //
}

Now, we create an instance of TaskLaunchRequest and send that as a payload of GenericMessage<TaskLaunchRequest> object. Then we can invoke the input channel of the Sink keeping the GenericMessage object in the channel.

现在,我们创建一个TaskLaunchRequest的实例,并将其作为GenericMessage<TaskLaunchRequest> 对象的有效载荷发送。然后我们可以调用Sinkinput通道,将GenericMessage对象保留在该通道中。

6. Conclusion

6.结论

In this tutorial, we’ve explored how Spring Cloud Task performs and how to configure it to log its events in a database. We also observed how Spring Batch job is defined and stored in the TaskRepository. Lastly, we explained how we can trigger Task from within Spring Cloud Stream.

在本教程中,我们已经探讨了Spring Cloud Task是如何执行的,以及如何配置它在数据库中记录其事件。我们还观察了Spring Batch作业是如何定义并存储在TaskRepository中的。最后,我们解释了如何从Spring Cloud Stream中触发任务。

As always, the code is available over on GitHub.

像往常一样,代码可在GitHub上获得