spring 任务调度_调度的五个基本职能

(1) 2024-10-01 12:12

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
spring 任务调度_调度的五个基本职能,希望能够帮助你!!!。

环境:Spring5.3.23


概述

Spring框架分别通过TaskExecutorTaskScheduler接口为任务的异步执行和调度提供了抽象。Spring还提供了在应用服务器环境中支持线程池或向CommonJ委托的那些接口的实现。最终,在公共接口背后使用这些实现可以抽象出Java SE 5、Java SE 6和Java EE环境之间的差异。

Spring还提供了集成类来支持Timer(1.3以来JDK的一部分)和Quartz调度器(https://www.quartz-scheduler.org/)的调度。你可以分别使用一个FactoryBean和对TimerTrigger实例的可选引用来设置这两个调度器。此外,Quartz调度器和计时器都有一个方便类,它允许你调用现有目标对象的方法(类似于普通的MethodInvokingFactoryBean操作)。

TaskExecutor抽象

执行器是JDK中线程池概念的名称。命名为“执行器”是因为无法保证底层实现实际上是一个池。执行器进程可以是单线程的,甚至可以是同步的。Spring的抽象隐藏了Java SE和Java EE环境之间的实现细节。

Spring的TaskExecutor接口是java.util.concurrent.Executor接口子类。它最初存在的主要原因是在使用线程池时抽象出对Java 5的需求。该接口有一个方法(execute(Runnable task)),该方法根据线程池的语义和配置接受一个要执行的任务。

TaskExecutor最初是为其他Spring组件提供线程池抽象的。ApplicationEventMulticaster、JMS的AbstractMessageListenerContainer和Quartz集成等组件都使用TaskExecutor抽象来共享线程。然而,如果bean需要线程池行为,也可以根据自己的需要使用这种抽象。

TaskExecutor类型

Spring包含了许多预构建的TaskExecutor实现。十有八九,你永远都不需要自己实现。Spring提供的变体如下。

  • SyncTaskExecutor

这个实现不会异步运行调用。相反,每次调用都发生在调用线程中。它主要用于不需要多线程的情况,例如简单的测试用例。

  • SimpleAsyncTaskExecutor

这个实现没有重用任何线程。相反,它为每次调用启动一个新线程。但它确实支持并发限制,该限制会阻塞任何超过并发限制的调用,直到释放一个任务槽。参考:ThreadPoolTaskExecutor

  • ConcurrentTaskExecutor

这个实现是java.util.concurrent.Executor实例的一个适配器。有一个替代方案(ThreadPoolTaskExecutor)将执行器配置参数暴露为bean属性。很少需要直接使用ConcurrentTaskExecutor。但是,如果ThreadPoolTaskExecutor不够灵活,不能满足需求,那么ConcurrentTaskExecutor是一种替代方案。

  • ThreadPoolTaskExecutor

这种实现是最常用的。它公开bean属性,用于配置java.util.concurrent.ThreadPoolExecutor,并将其包装在TaskExecutor中。如果你需要适应另一种java.util.concurrent.Executor,建议你使用ConcurrentTaskExecutor

  • WorkManagerTaskExecutor

这个实现使用CommonJ WorkManager作为它的后台服务提供者,它是用于在Spring应用程序上下文中的WebLogic或WebSphere上设置基于CommonJ的线程池集成的主要便利类。

  • DefaultManagedTaskExecutor

此实现在JSR-236兼容的运行时环境(例如Java EE 7+应用程序服务器)中使用jndi获得的ManagedExecutorService,取代了CommonJ WorkManager。

使用TaskExecutor

Spring的TaskExecutor实现被用作简单的JavaBeans。在下面的例子中,我们定义了一个bean,它使用ThreadPoolTaskExecutor异步打印出一组消息:

import org.springframework.core.task.TaskExecutor; public class TaskExecutorExample { private class MessagePrinterTask implements Runnable { private String message; public MessagePrinterTask(String message) { this.message = message; } public void run() { System.out.println(message); } } private TaskExecutor taskExecutor; public TaskExecutorExample(TaskExecutor taskExecutor) { this.taskExecutor = taskExecutor; } public void printMessages() { for(int i = 0; i < 25; i++) { taskExecutor.execute(new MessagePrinterTask("Message" + i)); } } }

正如所看到的,你将可运行线程添加到队列中,而不是从线程池中检索线程并自己执行它。然后TaskExecutor使用它的内部规则来决定任务何时运行。

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <property name="corePoolSize" value="5"/> <property name="maxPoolSize" value="10"/> <property name="queueCapacity" value="25"/> </bean> <bean id="taskExecutorExample" class="TaskExecutorExample"> <constructor-arg ref="taskExecutor"/> </bean>

TaskScheduler抽象

除了TaskExecutor抽象之外,Spring 3.0还引入了TaskScheduler,它提供了各种调度任务的方法,以便在未来的某个时候运行。下列代码清单给出了TaskScheduler接口的定义:

public interface TaskScheduler { ScheduledFuture schedule(Runnable task, Trigger trigger); ScheduledFuture schedule(Runnable task, Instant startTime); ScheduledFuture schedule(Runnable task, Date startTime); ScheduledFuture scheduleAtFixedRate(Runnable task, Instant startTime, Duration period); ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period); ScheduledFuture scheduleAtFixedRate(Runnable task, Duration period); ScheduledFuture scheduleAtFixedRate(Runnable task, long period); ScheduledFuture scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay); ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay); ScheduledFuture scheduleWithFixedDelay(Runnable task, Duration delay); ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay); }

最简单的方法是名为schedule的方法,它只接受一个Runnable对象和一个Date对象。这会导致任务在指定的时间之后运行一次。所有其他方法都能够调度任务重复运行。固定速率和固定延迟方法用于简单的周期性执行,但接受触发器的方法要灵活得多。

Trigger 接口

Trigger接口本质上是受JSR-236启发的,到Spring 3.0时还没有正式实现。Trigger的基本思想是,执行时间可以根据过去的执行结果甚至任意条件来确定。如果这些确定确实考虑了前面执行的结果,那么该信息在TriggerContext中是可用的。Trigger接口本身非常简单,如下列代码清单所示:

public interface Trigger { Date nextExecutionTime(TriggerContext triggerContext); }

TriggerContext是最重要的部分。它封装了所有相关的数据,如果有必要,将来可以进行扩展。TriggerContext是一个接口(默认使用SimpleTriggerContext实现)。下列代码清单展示了触发器实现中可用的方法。

public interface TriggerContext { Date lastScheduledExecutionTime(); Date lastActualExecutionTime(); Date lastCompletionTime(); }

Trigger实现

Spring提供了Trigger接口的两种实现。最有趣的是CronTrigger。支持基于cron表达式的任务调度。例如,下面的任务计划每小时运行15分钟,但只在工作日朝九晚五的“工作时间”:

scheduler.schedule(task, new CronTrigger("0 15 9-17 * * MON-FRI"));

另一种实现是一个周期性触发器,它接受一个固定的周期、一个可选的初始延迟值和一个布尔值,表示该周期应该被解释为固定速率还是固定延迟。由于TaskScheduler接口已经定义了以固定速率或固定延迟调度任务的方法,因此应该尽可能直接使用这些方法。PeriodicTrigger实现的价值在于,您可以在依赖于触发器抽象的组件中使用它。例如,允许周期性触发器、基于cron的触

发器甚至自定义触发器的实现交替使用可能会很方便。这样的组件可以利用依赖注入,这样您就可以在外部配置这样的触发器,从而轻松地修改或扩展它们。

TaskScheduler 实现

与Spring的TaskExecutor抽象一样,TaskScheduler安排的主要好处是应用程序的调度需求与部署环境解耦了。在部署到应用服务器环境时,这个抽象级别特别重要,因为应用程序本身不应该直接创建线程。对于这样的场景,Spring提供了一个TimerManagerTaskScheduler,它将任务委托给WebLogic或WebSphere上的CommonJ TimerManager,以及一个最新的DefaultManagedTaskScheduler,它将任务委托给Java EE 7+环境中的JSR-236 ManagedScheduledExecutorService。两者通常都配置了JNDI查找。

当不需要外部线程管理时,一种更简单的替代方案是在应用程序中设置本地ScheduledExecutorService,可以通过Spring的concurrentaskscheduler进行调整。为了方便起见,Spring还提供了ThreadPoolTaskScheduler,它在内部委托给ScheduledExecutorService来提供常见的bean风格的配置,类似于ThreadPoolTaskExecutor。在宽松的应用服务器环境中,这些变体非常适合本地嵌入式线程池设置,特别是在Tomcat和Jetty上。

完毕!!!

下一篇将会介绍如何使用异步执行及任务调度。

SpringBoot对Spring MVC都做了哪些事?(一)
SpringBoot对Spring MVC都做了哪些事?(二)
SpringBoot对Spring MVC都做了哪些事?(三)
SpringBoot对Spring MVC都做了哪些事?(四)
Spring Retry重试框架的应用
spring data jpa 高级应用

spring 任务调度_调度的五个基本职能_https://bianchenghao6.com/blog__第1张

spring 任务调度_调度的五个基本职能_https://bianchenghao6.com/blog__第2张

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

上一篇

已是最后文章

下一篇

已是最新文章

发表回复