优秀的编程知识分享平台

网站首页 > 技术文章 正文

Spring任务执行与调度配置及使用详解

nanyue 2024-12-12 14:11:50 技术文章 8 ℃

环境:Spring5.3.23


上一篇:《Spring强大的任务执行与调度

Springboot中配置

如果上下文中没有 Executor bean, Spring Boot会用合理的默认值自动配置ThreadPoolTaskExecutor,它可以自动关联到异步任务执行(@EnableAsync)和Spring MVC异步请求处理。

如果你在上下文中定义了自定义 Executor,常规任务执行(例如@EnableAsync)会透明地使用它,但Spring MVC(异步处理)支持不会配置它,因为它需要AsyncTaskExecutor实现(名为applicationTaskExecutor)。根据目标安排,可以将你的Executor更改为ThreadPoolTaskExecutor,或者同时定义一个ThreadPoolTaskExecutor和一个包装自定义执行器的AsyncConfigurer。

自动配置的TaskExecutorBuilder让你可以轻松地创建实例,重现自动配置默认做的事情。

线程池使用8个核心线程,这些线程可以根据负载大小增减。这些默认设置可以使用spring.task.execution命名空间进行微调,如下面的例子所示。

spring:
  task:
    execution:
      pool:
        max-size: 16
        queue-capacity: 100
        keep-alive: "10s"

这将修改线程池,使用有界队列,以便在队列满时(100个任务),线程池增加到最多16个线程。当线程空闲10秒(而不是默认的60秒)时,会回收线程,因此池的收缩会更积极。

如果需要关联到计划任务执行,ThreadPoolTaskScheduler也可以自动配置(例如@EnableScheduling)。线程池默认使用一个线程,可以使用spring.task.scheduling命名空间对其设置进行微调,如下面的例子所示:

spring:
  task:
    scheduling:
      thread-name-prefix: "scheduling-"
      pool:
        size: 2

如果需要创建自定义的执行器或调度器,TaskExecutorBuilder bean和TaskSchedulerBuilder bean都可以在上下文中使用。

Spring配置

  • 启用功能
@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {
}
  • @Scheduled注解

通过给方法添加@Scheduled注解,以及触发器元数据。例如,下面的方法以固定的延迟每5秒(5000毫秒)调用一次,这意味着周期是从前面每次调用的完成时间计算出来的。

@Scheduled(fixedDelay = 5000)
public void doSomething() {
}

默认情况下,毫秒将被用作固定延迟、固定速率和初始延迟值的时间单位。如果你想使用不同的时间单位,比如秒或分钟,可以通过@Scheduled中的timeUnit属性进行配置。

@Scheduled(fixedDelay = 5, timeUnit = TimeUnit.SECONDS)
public void doSomething() {
}

如果需要固定速率的执行,可以在注释中使用fixedRate属性。下面的方法每5秒调用一次(在每次调用的连续开始时间之间测量)。

@Scheduled(fixedRate = 5, timeUnit = TimeUnit.SECONDS)
public void doSomething() {
}

对于固定延迟和固定速率的任务,你可以通过指定第一次执行方法之前等待的时间来指定初始延迟,如下面的fixedRate示例所示。

@Scheduled(initialDelay = 1000, fixedRate = 5000)
public void doSomething() {
}

如果简单的周期性调度表达能力不够,可以提供一个cron表达式。下面的例子只在工作日运行:

@Scheduled(cron="*/5 * * * * MON-FRI")
public void doSomething() {
}

从Spring Framework 4.3开始,任何作用域的bean都支持@Scheduled方法。

确保没有在运行时初始化同一个@Scheduled注解类的多个实例,除非你确实希望为每个此类实例安排回调。与此相关,请确保不要在带有@Scheduled注解并在容器中注册为常规Spring bean的bean类上使用@Configurable。否则,就会得到两次初始化(一次通过容器,一次通过@Configurable方面),每个@Scheduled方法都会被调用两次。

  • @Async注解

你可以为方法提供@Async注解,以便异步调用该方法。换句话说,调用者在调用后立即返回,而该方法的实际执行发生在已提交给Spring TaskExecutor的任务中。在最简单的情况下,可以把注解应用到返回void的方法上,如下面的例子所示:

@Async
void doSomething() {
}

与使用@Scheduled注解的方法不同,这些方法可以接收参数,因为它们是在运行时由调用者以“正常”方式调用的,而不是从容器管理的计划任务中调用的。例如,下面的代码就是@Async注解的合法应用:

@Async
void doSomething(String s) {
}

即使是有返回值的方法也可以异步调用。然而,这种方法的返回值必须是future类型的。这仍然提供了异步执行的好处,因此调用者可以在调用get()之前执行其他任务。下面的例子展示了如何在返回值的方法上使用@Async:

@Async
Future<String> returnSomething(int i) {
}

@Async方法不仅可以声明常规的java.util.concurrent.Future返回类型,还可以声明Spring的org.springframework.util.concurrent.ListenableFuture,或者从Spring 4.2开始,JDK 8的java.util.concurrent.CompletableFuture可以与异步任务进行更丰富的交互,也可以与进一步的处理步骤立即组合。

你不能将@Async@PostConstruct这样的生命周期回调结合使用。要异步初始化Spring bean,当前必须使用一个单独的初始化Spring bean,然后在目标上调用@Async注解方法,如下面的例子所示。

public class SampleBeanImpl implements SampleBean {
  @Async
  void doSomething() {
  }

}

public class SampleBeanInitializer {
  private final SampleBean bean;
  public SampleBeanInitializer(SampleBean bean) {
    this.bean = bean;
  }
  @PostConstruct
  public void initialize() {
    bean.doSomething();
  }
}
  • 使用@Async对执行器进行限定

默认情况下,当在方法上指定@Async时,使用的执行器是启用async支持时配置的执行器,即“注解驱动”元素(如果使用XML或AsyncConfigurer实现的话)。不过,如果需要在执行给定方法时指定默认执行器以外的执行器,可以使用@Async注解的value属性。如下面的例子所示:

@Async("otherExecutor")
void doSomething(String s) {
}
  • 使用@Async管理异常

@Async方法有Future类型的返回值时,管理方法执行期间抛出的异常很容易,因为这个异常是在对Future的结果调用get方法时抛出的。然而,如果返回类型为void,则异常不会被捕获,无法传输。你可以提供一个AsyncUncaughtExceptionHandler来处理这种异常。如下面的例子所示:

public class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
  @Override
  public void handleUncaughtException(Throwable ex, Method method, Object... params) {
  }
}

完毕!!!

关注我长期更新

SpringBoot对Spring MVC都做了哪些事?(一)
SpringBoot对Spring MVC都做了哪些事?(二)
SpringBoot对Spring MVC都做了哪些事?(三)
SpringBoot对Spring MVC都做了哪些事?(四)
Spring Retry重试框架的应用
spring data jpa 高级应用
Spring MVC 异常处理方式
Spring容器这些扩展点你都清楚了吗?
Spring MVC 异步请求方式
Spring事务实现原理源码分析
Spring中的@Configuration注解你真的了解吗?
Spring 强大的数据验证功能
Spring容器这些扩展点你都清楚了吗?
Spring是如何解决循环依赖的?

Tags:

最近发表
标签列表