在这个Spring Boot的教程中,我们将看看Spring Boot调度器***。我们将看到如何用Spring Boot调度任务。在这篇文章中,让我们看看Spring @Scheduled注释*。
Spring Boot使用**@Scheduled注解**来安排任务。它在内部使用TaskScheduler
接口来调度注释方法的执行。在使用该注解时,我们可能需要遵循某些规则。
让我们为我们的***Spring Boot调度器创建一个简单的应用程序。我们有以下选项来创建一个Spring Boot项目。
这就是我们的pom.xml
的样子。
<?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.1.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.javadevjournal</groupId>
<artifactId>spring-boot-scheduler</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-scheduler</name>
<description>Spring Boot schedule sample application</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
启用调度;我们需要添加@EnableScheduling
注解。我们有以下2个选项可以在我们的应用程序中添加这个注释。
@EnableScheduling
注解。import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class SpringBootSchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootSchedulerApplication.class, args);
}
}
@EnableScheduling
注解创建了一个后台任务执行器。
任何调度器的主要工作是调度任务。Spring Boot使创建一个调度任务变得很容易。我们只需要用**@Scheduled
注解来注解方法。让我们看一下其中一个例子,以便更好地理解。
@Component
public class SayHelloTask {
private static final Logger LOG = LoggerFactory.getLogger(SayHelloTask.class);
@Scheduled(fixedRate = 1000)
public void sayHello(){
LOG.info("Hello from our simple scheduled method");
}
}
让我们看一下一些重要的要点。
@Scheduled
注解定义了调度(例如,方法何时运行等)。如果我们运行这个应用程序,在应用程序启动后,你会在控制台看到以下输出。
2019-10-10 20:53:12.447 INFO 45786 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method
2019-10-10 20:53:13.448 INFO 45786 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method
2019-10-10 20:53:14.446 INFO 45786 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method
2019-10-10 20:53:15.450 INFO 45786 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method
2019-10-10 20:53:16.448 INFO 45786 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method
2019-10-10 20:53:17.446 INFO 45786 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method
在下一节中,我们将看到一些可以与Scheduled
注解一起使用的参数。
要在一个固定的内部安排一个方法触发器,我们可以使用fixedRate
注解中的@Scheduled
参数。让我们举个例子,我们想每隔1秒执行一次方法。
@Scheduled(fixedRate = 1000)
public void sayHello(){
LOG.info("Hello from our simple scheduled method");
}
假设我们希望在最后一次执行和下一次执行的开始之间有一个固定的延迟。我们可以在这个注释中使用fixedDelay
参数。这个参数计算的是最后一次调用完成后的延迟。
@Scheduled(fixedDelay = 2000)
public void fixedDelayExample(){
LOG.info("Hello from our Fixed delay method");
}
这就是输出的样子。
2019-10-10 21:19:38.331 INFO 46159 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
2019-10-10 21:19:40.333 INFO 46159 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
2019-10-10 21:19:42.345 INFO 46159 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
2019-10-10 21:19:44.346 INFO 46159 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
这里,任务被触发的延迟时间为2秒。为了更好地理解,让我们给我们的方法添加一些变化。让我们假设,我们的任务需要3分钟来完成,在这种情况下,下一次执行应该在5秒内开始(3秒完成,2秒延迟)。
@Scheduled(fixedDelay = 2000)
public void fixedDelayExample() {
LOG.info("Hello from our Fixed delay method");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException ie) {
LOG.error("Got Interrupted {}", ie);
}
}
当我们运行这段代码时,我们将有以下输出。
2019-10-10 21:25:11.623 INFO 46242 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
2019-10-10 21:25:16.629 INFO 46242 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
2019-10-10 21:25:21.633 INFO 46242 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our Fixed delay method
总的延迟为5秒。
我们也可以通过在计划任务中添加@Async注解来启用并行调度。让我们看一下这个例子。
@EnableAsync
public class ParallelSchedulingExample {
@Async
@Scheduled(fixedDelay = 2000)
public void fixedDelayExample() {
LOG.info("Hello from our Fixed delay method");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException ie) {
LOG.error("Got Interrupted {}", ie);
}
}
}
我们也可以使用initialDelay
参数来延迟任务的第一次执行,延迟的时间为指定的毫秒。我们可以根据我们的要求将这个参数与fixedRate
和fixedDelay
结合起来。
@Scheduled(fixedRate = 2000, initialDelay = 5000)
public void scheduleTaskWithInitialDelay() {
LOG.info("Fixed Rate Task with Initial Delay");
}
@Scheduled(fixedRate = 2000, fixedDelay = 5000)
public void scheduleTaskWithInitialDelay() {
LOG.info("Fixed Rate Task with Initial Delay");
}
当我们运行我们的应用程序时,我们将有以下输出。
2019-10-10 21:58:01.415 INFO 46959 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Fixed Rate Task with Initial Delay
2019-10-10 21:58:03.412 INFO 46959 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Fixed Rate Task with Initial Delay
2019-10-10 21:58:05.417 INFO 46959 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Fixed Rate Task with Initial Delay
2019-10-10 21:58:07.415 INFO 46959 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Fixed Rate Task with Initial Delay
Cron表达式是一种灵活而强大的安排任务的方式。该模式是一个由六个单空格分隔的字段组成的列表:代表秒、分、小时、日、月、工作日。月和工作日的名称可以用英文名称的前三个字母来表示。在这个例子中,我们使用cron表达式为每1分钟调度一次任务。
@Scheduled(cron = "0 * * * * ?")
public void scheduleTaskWithCronExpression() {
LOG.info("Example to show how cron expression can be used");
}
当我们运行我们的应用程序时,它将在每1分钟内执行任务。这就是输出结果的模样。
2019-10-12 19:25:00.003 INFO 74830 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Example to show how cron expression can be used
2019-10-12 19:26:00.003 INFO 74830 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Example to show how cron expression can be used
Spring Boot和Spring提供了一个强大的机制,可以使用属性文件将你的配置外部化。在开发任何企业应用程序时,将配置外部化总是很好的做法,以避免硬编码。它还有助于以下方面的工作
让我们使用Spring表达式语言,通过属性文件将日程表表达式外部化,这就是新代码的样子。
@Scheduled($ {
fixedrate.value
})
public void sayHello() {
LOG.info("Hello from our simple scheduled method");
}
@Scheduled($ {
fixeddelay.value
})
public void fixedDelayExample() {
LOG.info("Hello from our Fixed delay method");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException ie) {
LOG.error("Got Interrupted {}", ie);
}
}
@Scheduled($ {
cron.expression
})
public void scheduleTaskWithCronExpression() {
LOG.info("Example to show how cron expression can be used");
}
@Scheduled
注解将执行默认线程池中的任务。Spring在启动时创建了大小为1的默认线程池。让我们运行之前的例子来验证这一声明。
2019-10-13 11:23:13.224 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
2019-10-13 11:23:14.225 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
2019-10-13 11:23:15.225 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
2019-10-13 11:23:16.225 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
2019-10-13 11:23:17.224 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
2019-10-13 11:23:18.221 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
2019-10-13 11:23:19.225 INFO 88646 --- [ scheduling-1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: scheduling-1
我们在日志中添加了以下一行来打印线程名称:Thread.currentThread().getName()
。Spring提供了创建自定义线程池的灵活性,并使用自定义线程池执行所有任务。让我们看看如何为我们的应用程序创建和配置自定义线程池。
@Configuration
public class CustomThreadPoolConfig implements SchedulingConfigurer {
private final int CUSTOM_POOL_SIZE = 5;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(CUSTOM_POOL_SIZE);
threadPoolTaskScheduler.setThreadNamePrefix("javadevjournal");
threadPoolTaskScheduler.initialize();
//let's register our custom thread pool scheduler
scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
现在,当我们运行我们的应用程序时,Spring将使用新的线程池,这就是输出的样子。
2019-10-13 11:32:54.570 INFO 88821 --- [javadevjournal1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal1
2019-10-13 11:32:55.571 INFO 88821 --- [javadevjournal2] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal2
2019-10-13 11:32:56.571 INFO 88821 --- [javadevjournal1] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal1
2019-10-13 11:32:57.571 INFO 88821 --- [javadevjournal3] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal3
2019-10-13 11:32:58.572 INFO 88821 --- [javadevjournal3] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal3
2019-10-13 11:32:59.571 INFO 88821 --- [javadevjournal3] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal3
2019-10-13 11:33:00.569 INFO 88821 --- [javadevjournal3] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal3
2019-10-13 11:33:01.572 INFO 88821 --- [javadevjournal3] c.j.schedule.task.SayHelloTask : Hello from our simple scheduled method, current thread is :: javadevjournal3</code?
对于简单的用例来说,Spring调度是一个不错的选择,但如果你正在寻找更高级的调度框架(比如持久化等),可以考虑使用Quartz调度器。
###总结
在这篇文章中,我们研究了Spring boot scheduler***。我们了解了配置和使用@Scheduled*注解的方法。我们看到了通过传递不同的参数来定制@Scheduled
注释的不同选项。在这篇文章的最后,我们看到了如何为我们的应用程序配置自定义线程池。这篇文章的源代码可以在GitHub上找到。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.javadevjournal.com/spring-boot/spring-boot-scheduler/
内容来源于网络,如有侵权,请联系作者删除!