Spring Cloud Task 快速入门

Spring Cloud Task 快速入门

Spring Cloud Task 简要介绍

Spring Cloud Task 允许用户使用Spring Cloud 开发和运行一个短生命周期的微服务。它主要就是来解决 short-lived microservices的问题,因为一般的服务都是长时间一直保持运行的,但是有很多服务并不需要一直保持运行;比如一些定时任务或者临时任务。所以Spring Cloud Task可以让你更简单的创建短时运行的微服务。

运行环境

需要安装Java(Java 8或更高版本。要进行构建,还需要安装Maven

数据库环境

Spring Cloud Task使用关系数据库来存储已执行Task的结果。当然可以运行在无数据库的环境下,仅存储在内存中,无法进行数据持久化。现版本的Spring Cloud Task支持的数据库如下所示:

  • DB2
  • H2
  • HSQLDB
  • MySql
  • Oracle
  • Postgres
  • SqlServer

第一个 Spring Cloud Task 应用

访问Spring Initialzr网站创建一个mavem项目,如下:

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.4.0-SNAPSHOT</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>spring-cloud-task-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-cloud-task-demo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>2020.0.0-SNAPSHOT</spring-cloud.version>
	</properties>

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

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
		</repository>
		<repository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
		</pluginRepository>
		<pluginRepository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</pluginRepository>
	</pluginRepositories>

</project>

一个Spring Cloud Task 项目必须同时是一个Spring Boot项目,在上面的POM文件中,我们通过指定spring-boot-starter-parent为该项目的父项目来将它转化为Spring Boot项目。

Spring Boot提供了许多额外的 “Starter POMs”,很多starter对Spring Cloud Task来说都是非常有用的,如spring-boot-starter-batch,spring-boot-starter-jdbc等,也有许多starter对其没有什么帮助,如spring-boot-starter-web.Spring Boot自带的bean探测器会自动扫描classpath下的starter,spring-boot-starter-web如果在classpath下,在启动应用时就会自动启动Servlet容器

参考:[spring cloud task]1 简介与示例

上面关键的spring cloud task的依赖就是:

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

然后我们的代码如下:

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.context.annotation.Bean;

@SpringBootApplication
@EnableTask
public class HelloWorldApplication {

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

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

	public static class HelloWorldCommandLineRunner implements CommandLineRunner {

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

接下来我们需要打开application.properties,路径在src/main/resources,然后添加两个配置:

# 将Spring Cloud Task的日志记录设置为DEBUG, 可以更方便的让我们调试应用
logging.level.org.springframework.cloud.task=DEBUG
# 设置application name (会转为task name)
spring.application.name=HelloWorld

接下来我们直接启动一下应用:


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

2020-07-18 16:41:40.578  INFO 4300 --- [           main] com.example.HelloWorldApplication        : Starting HelloWorldApplication using Java 1.8.0_92 on C with PID 4300 (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 16:41:40.581  INFO 4300 --- [           main] com.example.HelloWorldApplication        : No active profile set, falling back to default profiles: default
2020-07-18 16:41:41.324  INFO 4300 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-07-18 16:41:41.497  INFO 4300 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2020-07-18 16:41:41.512 DEBUG 4300 --- [           main] o.s.c.t.c.SimpleTaskAutoConfiguration    : Using org.springframework.cloud.task.configuration.DefaultTaskConfigurer TaskConfigurer
2020-07-18 16:41:41.513 DEBUG 4300 --- [           main] o.s.c.t.c.DefaultTaskConfigurer          : No EntityManager was found, using DataSourceTransactionManager
2020-07-18 16:41:41.799 DEBUG 4300 --- [           main] o.s.c.t.r.s.TaskRepositoryInitializer    : Initializing task schema for h2 database
2020-07-18 16:41:41.972 DEBUG 4300 --- [           main] o.s.c.t.r.support.SimpleTaskRepository   : Creating: TaskExecution{executionId=0, parentExecutionId=null, exitCode=null, taskName='HelloWorld', startTime=Sat Jul 18 16:41:41 GMT+08:00 2020, endTime=null, exitMessage='null', externalExecutionId='null', errorMessage='null', arguments=[]}
2020-07-18 16:41:42.013  INFO 4300 --- [           main] com.example.HelloWorldApplication        : Started HelloWorldApplication in 1.836 seconds (JVM running for 4.712)
Hello, World!
2020-07-18 16:41:42.031 DEBUG 4300 --- [           main] o.s.c.t.r.support.SimpleTaskRepository   : Updating: TaskExecution with executionId=1 with the following {exitCode=0, endTime=Sat Jul 18 16:41:42 GMT+08:00 2020, exitMessage='null', errorMessage='null'}
2020-07-18 16:41:42.038  INFO 4300 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2020-07-18 16:41:42.041  INFO 4300 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

Process finished with exit code 0

可以看到我们的"Hello, World!"已经被打印出来了。

我们可以从日志中看出到其中几条重要的输出。

2020-07-18 16:41:41.972 DEBUG 4300 --- [           main] o.s.c.t.r.support.SimpleTaskRepository   : Creating: TaskExecution{executionId=0, parentExecutionId=null, exitCode=null, taskName='HelloWorld', startTime=Sat Jul 18 16:41:41 GMT+08:00 2020, endTime=null, exitMessage='null', externalExecutionId='null', errorMessage='null', arguments=[]}
2020-07-18 16:41:42.013  INFO 4300 --- [           main] com.example.HelloWorldApplication        : Started HelloWorldApplication in 1.836 seconds (JVM running for 4.712)
Hello, World!
2020-07-18 16:41:42.031 DEBUG 4300 --- [           main] o.s.c.t.r.support.SimpleTaskRepository   : Updating: TaskExecution with executionId=1 with the following {exitCode=0, endTime=Sat Jul 18 16:41:42 GMT+08:00 2020, exitMessage='null', errorMessage='null'}

首先就是Create了一个TaskExecution对象,标志task开始启动,记录了startTime,内容如下:

TaskExecution{executionId=0, parentExecutionId=null, exitCode=null, taskName='HelloWorld', startTime=Sat Jul 18 16:41:41 GMT+08:00 2020, endTime=null, exitMessage='null', externalExecutionId='null', errorMessage='null', arguments=[]}

然后就是打印出了"Hello, World!", 接下来就是更新task的状态了,所以又update了TaskExecution对象,记录了endTime,还有exitCode,值为0表示成功了。

TaskExecution{exitCode=0, endTime=Sat Jul 18 16:41:42 GMT+08:00 2020, exitMessage='null', errorMessage='null'}

还有从日志也可以看出,我们的demo是使用嵌入式H2数据库记录任务的结果(因为我们引入了jdbc和H2)。这个H2嵌入式数据库不是针对生产环境的实用解决方案,因为一旦任务结束,H2 DB就会消失。

@EnableTask 注解

通过@EnableTask注解可以开启我们Spring Cloud Task的功能,他会默认加载配置类SimpleTaskConfiguration,这个task配置类SimpleTaskConfiguration会自动注册TaskRepository作为基础组件管理后面的task。

注意:如果我们没有在数据库中持久化存储task相关信息,TaskRepository仍然是开箱即用的,他会在内存中纪录每个task的结果。

当demo目运行时,Spring Boot会执行我们的HelloWorldCommandLineRunner类并在标准输出流中打印 “Hello, World!”

CommandLineRunner和ApplicationRunner

我们可以通过实现CommandLineRunnerApplicationRunner的run方法来完成我们需要的逻辑代码。

一个task的生命周期就是从CommandLineRunner#run方法或者ApplicationRunner#run方法开始,直到该task的所有任务都被执行完成。Spring Boot允许应用中有多个 *Runner 接口的实现。

比如我们把我们的代码改造成如下:

package com.example;

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
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.context.annotation.Bean;

@SpringBootApplication
@EnableTask
public class HelloWorldApplication {

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

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

	public static class HelloWorldCommandLineRunner implements CommandLineRunner {

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


		@Override
		public void run(ApplicationArguments args) throws Exception {
			System.out.println("Hello, World!!~~~");
		}
	}
}

然后我们运行之后会发现:


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

2020-07-18 16:58:36.496  INFO 14292 --- [           main] com.example.HelloWorldApplication        : Starting HelloWorldApplication using Java 1.8.0_92 on C with PID 14292 (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 16:58:36.499  INFO 14292 --- [           main] com.example.HelloWorldApplication        : No active profile set, falling back to default profiles: default
2020-07-18 16:58:37.327  INFO 14292 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-07-18 16:58:37.506  INFO 14292 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2020-07-18 16:58:37.519 DEBUG 14292 --- [           main] o.s.c.t.c.SimpleTaskAutoConfiguration    : Using org.springframework.cloud.task.configuration.DefaultTaskConfigurer TaskConfigurer
2020-07-18 16:58:37.520 DEBUG 14292 --- [           main] o.s.c.t.c.DefaultTaskConfigurer          : No EntityManager was found, using DataSourceTransactionManager
2020-07-18 16:58:37.792 DEBUG 14292 --- [           main] o.s.c.t.r.s.TaskRepositoryInitializer    : Initializing task schema for h2 database
2020-07-18 16:58:37.901 DEBUG 14292 --- [           main] o.s.c.t.r.support.SimpleTaskRepository   : Creating: TaskExecution{executionId=0, parentExecutionId=null, exitCode=null, taskName='HelloWorld', startTime=Sat Jul 18 16:58:37 GMT+08:00 2020, endTime=null, exitMessage='null', externalExecutionId='null', errorMessage='null', arguments=[]}
2020-07-18 16:58:37.936  INFO 14292 --- [           main] com.example.HelloWorldApplication        : Started HelloWorldApplication in 1.849 seconds (JVM running for 4.313)
Hello, World!!~~~
Hello, World!
2020-07-18 16:58:37.953 DEBUG 14292 --- [           main] o.s.c.t.r.support.SimpleTaskRepository   : Updating: TaskExecution with executionId=1 with the following {exitCode=0, endTime=Sat Jul 18 16:58:37 GMT+08:00 2020, exitMessage='null', errorMessage='null'}
2020-07-18 16:58:37.960  INFO 14292 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2020-07-18 16:58:37.961  INFO 14292 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

Process finished with exit code 0

分别打印了"Hello, World!!~~~“和"Hello, World!”,所以在你的代码中有多个 *Runner 接口的实现,Spring Boot都会帮你执行里面的run方法。

测试

package com.example;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@ExtendWith(OutputCaptureExtension.class)
class HelloWorldApplicationTest {

    @Test
    public void contextLoads(CapturedOutput capturedOutput){
        assertTrue(capturedOutput.toString().contains("Hello, World!"));
        assertTrue(capturedOutput.toString().contains("Hello, World!!~~~"));
    }
}

在这里插入图片描述

注意:如果你使用spring的测试套件来管理测试时应用上下文时,如果由Spring Cloud Task来关闭应用程序上下文,可能会抛出java.lang.IllegalStateException: The ApplicationContext loaded for **** is not active. Ensure that the context has not been closed programmatically.异常。@TestPropertySource(properties = {"spring.cloud.task.closecontext_enable=false"})可以关闭 Spring Cloud Task的自动关闭上下文的功能。

参考

Spring Cloud Task 简单示例

spring cloud task Demo搭建

Run JUnit Jupiter test with Spring 4.1 and JUnit4 Runner in IntelliJ

Spring Cloud Task 简单示例

[spring cloud task]1 简介与示例

Spring Cloud Task 官方文档

SpringBoot : Spring Cloud Task | Example | Java Techie YouTube视频

源代码

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值