タスクの実行とスケジューリング

コンテキスト内に Executor (標準 Javadoc) Bean がない場合、Spring Boot は AsyncTaskExecutor (Javadoc) を自動構成します。仮想スレッドが有効になっている場合 ( Java 21+ を使用し、spring.threads.virtual.enabled を true に設定)、これは仮想スレッドを使用する SimpleAsyncTaskExecutor (Javadoc) になります。それ以外の場合は、適切なデフォルトを持つ ThreadPoolTaskExecutor (Javadoc) になります。

カスタム Executor (標準 Javadoc) Bean が定義されていない限り、自動構成された AsyncTaskExecutor (Javadoc) は次の統合に使用されます。

  • AsyncConfigurer (Javadoc) 型の Bean が定義されていない限り、@EnableAsync (Javadoc) を使用して非同期タスクを実行します。

  • Spring for GraphQL のコントローラーメソッドからの Callable (標準 Javadoc) 戻り値の非同期処理。

  • Spring MVC での非同期リクエスト処理。

  • Spring、WebFlux でのブロック実行のサポート。

  • Spring、WebSocket の受信および送信メッセージチャネルに使用されます。

  • JPA リポジトリのブートストラップモードに基づいた、JPA 用のブートストラップエグゼキュータ。

  • ApplicationContext 内の Bean のバックグラウンド初期化用のブートストラップエグゼキュータ。

このアプローチはほとんどのシナリオで機能しますが、Spring Boot を使用すると自動構成された AsyncTaskExecutor (Javadoc) をオーバーライドできます。デフォルトでは、カスタム Executor (標準 Javadoc) Bean が登録されると、自動構成された AsyncTaskExecutor (Javadoc) はバックオフされ、カスタム Executor (標準 Javadoc) が通常のタスク実行(@EnableAsync (Javadoc) 経由)に使用されます。

ただし、Spring MVC、Spring、WebFlux、Spring GraphQL はすべて、applicationTaskExecutor という名前の Bean を必要とします。Spring MVC および Spring、WebFlux の場合、この Bean は AsyncTaskExecutor (Javadoc) 型である必要がありますが、Spring GraphQL ではこの型要件は強制されません。

Spring、WebSocket、JPA は、この型の Bean が 1 つだけ使用可能であるか、applicationTaskExecutor という名前の Bean が定義されている場合、AsyncTaskExecutor (Javadoc) を使用します。

最後に、ApplicationContext のブートストラップエグゼキュータは、bootstrapExecutor という名前の Bean が定義されていない限り、applicationTaskExecutor という名前の Bean を使用します。

次のコードスニペットは、Spring MVC、Spring、WebFlux、Spring GraphQL、Spring、WebSocket、JPA、Bean のバックグラウンド初期化で使用するカスタム AsyncTaskExecutor (Javadoc) を登録する方法を示しています。

  • Java

  • Kotlin

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;

@Configuration(proxyBeanMethods = false)
public class MyTaskExecutorConfiguration {

	@Bean("applicationTaskExecutor")
	SimpleAsyncTaskExecutor applicationTaskExecutor() {
		return new SimpleAsyncTaskExecutor("app-");
	}

}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.task.SimpleAsyncTaskExecutor

@Configuration(proxyBeanMethods = false)
class MyTaskExecutorConfiguration {

	@Bean("applicationTaskExecutor")
	fun applicationTaskExecutor(): SimpleAsyncTaskExecutor {
		return SimpleAsyncTaskExecutor("app-")
	}

}

アプリケーションコンテキストに @Primary (Javadoc) Bean または型 Executor (標準 Javadoc) または AsyncConfigurer (Javadoc) の taskExecutor という名前の Bean が存在しない場合は、applicationTaskExecutor Bean も通常のタスク実行に使用されます。

自動構成された AsyncTaskExecutor も applicationTaskExecutor の Bean も定義されていない場合、アプリケーションは Spring Framework の動作に従い、通常のタスク実行(@EnableAsync (Javadoc) )に taskExecutor という名前の Bean をデフォルトで使用します。ただし、この Bean は Spring MVC、Spring、WebFlux、Spring の GraphQL では使用されません。ただし、Bean の型が AsyncTaskExecutor (Javadoc) の場合、Spring、WebSocket、JPA では使用できます。

アプリケーションで、異なる統合用に複数の Executor Bean (1 つは @EnableAsync (Javadoc) を使用した通常のタスク実行用、もう 1 つは Spring MVC、Spring、WebFlux、Spring、WebSocket、JPA 用) が必要な場合は、次のように構成できます。

  • Java

  • Kotlin

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration(proxyBeanMethods = false)
public class MyTaskExecutorConfiguration {

	@Bean("applicationTaskExecutor")
	SimpleAsyncTaskExecutor applicationTaskExecutor() {
		return new SimpleAsyncTaskExecutor("app-");
	}

	@Bean("taskExecutor")
	ThreadPoolTaskExecutor taskExecutor() {
		ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
		threadPoolTaskExecutor.setThreadNamePrefix("async-");
		return threadPoolTaskExecutor;
	}

}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.task.SimpleAsyncTaskExecutor
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor


@Configuration(proxyBeanMethods = false)
class MyTaskExecutorConfiguration {

	@Bean("applicationTaskExecutor")
	fun applicationTaskExecutor(): SimpleAsyncTaskExecutor {
		return SimpleAsyncTaskExecutor("app-")
	}

	@Bean("taskExecutor")
	fun taskExecutor(): ThreadPoolTaskExecutor {
		val threadPoolTaskExecutor = ThreadPoolTaskExecutor()
		threadPoolTaskExecutor.setThreadNamePrefix("async-")
		return threadPoolTaskExecutor
	}

}

自動構成された ThreadPoolTaskExecutorBuilder (Javadoc) または SimpleAsyncTaskExecutorBuilder (Javadoc) を使用すると、自動構成のデフォルトの動作を複製する AsyncTaskExecutor (Javadoc) 型のインスタンスを簡単に作成できます。

  • Java

  • Kotlin

import org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;

@Configuration(proxyBeanMethods = false)
public class MyTaskExecutorConfiguration {

	@Bean
	SimpleAsyncTaskExecutor taskExecutor(SimpleAsyncTaskExecutorBuilder builder) {
		return builder.build();
	}

}
import org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.task.SimpleAsyncTaskExecutor

@Configuration(proxyBeanMethods = false)
class MyTaskExecutorConfiguration {

	@Bean
	fun taskExecutor(builder: SimpleAsyncTaskExecutorBuilder): SimpleAsyncTaskExecutor {
		return builder.build()
	}

}

Bean という名前の taskExecutor が選択できない場合は、Bean を @Primary (Javadoc) としてマークするか、AsyncConfigurer (Javadoc) の Bean を定義して、通常のタスク実行を @EnableAsync (Javadoc) で処理する Executor を指定します。次の例は、これを実現する方法を示しています。

  • Java

  • Kotlin

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;

@Configuration(proxyBeanMethods = false)
public class MyTaskExecutorConfiguration {

	@Bean
	AsyncConfigurer asyncConfigurer(ExecutorService executorService) {
		return new AsyncConfigurer() {

			@Override
			public Executor getAsyncExecutor() {
				return executorService;
			}

		};
	}

	@Bean
	ExecutorService executorService() {
		return Executors.newCachedThreadPool();
	}

}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.scheduling.annotation.AsyncConfigurer
import java.util.concurrent.Executor
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

@Configuration(proxyBeanMethods = false)
class MyTaskExecutorConfiguration {

	@Bean
	fun asyncConfigurer(executorService: ExecutorService): AsyncConfigurer {
		return object : AsyncConfigurer {
			override fun getAsyncExecutor(): Executor {
				return executorService
			}
		}
	}

	@Bean
	fun executorService(): ExecutorService {
		return Executors.newCachedThreadPool()
	}

}

自動構成された AsyncTaskExecutor (Javadoc) を維持しながらカスタム Executor (標準 Javadoc) を登録するには、次の例に示すように、カスタム Executor (標準 Javadoc) Bean を作成し、その @Bean (Javadoc) アノテーションに defaultCandidate=false 属性を設定します。

  • Java

  • Kotlin

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyTaskExecutorConfiguration {

	@Bean(defaultCandidate = false)
	@Qualifier("scheduledExecutorService")
	ScheduledExecutorService scheduledExecutorService() {
		return Executors.newSingleThreadScheduledExecutor();
	}

}
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService

@Configuration(proxyBeanMethods = false)
class MyTaskExecutorConfiguration {

	@Bean(defaultCandidate = false)
	@Qualifier("scheduledExecutorService")
	fun scheduledExecutorService(): ScheduledExecutorService {
		return Executors.newSingleThreadScheduledExecutor()
	}

}

この場合、自動構成された AsyncTaskExecutor (Javadoc) を維持しながら、カスタム Executor (標準 Javadoc) を他のコンポーネントにオートワイヤーできます。ただし、@Autowired (Javadoc) と併せて @Qualifier (Javadoc) アノテーションを使用することを忘れないでください。

これが不可能な場合は、次のようにして、Spring Boot に AsyncTaskExecutor (Javadoc) を自動構成するようにリクエストできます。

  • プロパティ

  • YAML

spring.task.execution.mode=force
spring:
  task:
    execution:
      mode: force

自動構成された AsyncTaskExecutor (Javadoc) は、カスタム Executor (標準 Javadoc) Bean が登録されている場合でも、すべての統合(@Primary (Javadoc) としてマークされているものを含む)で自動的に使用されます。これらの統合には以下が含まれます。

  • AsyncConfigurer (Javadoc) Bean が存在しない場合は、非同期タスク実行 ( @EnableAsync (Javadoc) )。

  • Spring for GraphQL はコントローラーメソッドからの Callable (標準 Javadoc) 戻り値を非同期的に処理します。

  • Spring MVC の非同期リクエスト処理。

  • Spring、WebFlux のブロッキング実行サポート。

  • Spring、WebSocket の受信および送信メッセージチャネルに使用されます。

  • JPA リポジトリのブートストラップモードに基づいた、JPA 用のブートストラップエグゼキュータ。

  • bootstrapExecutor という名前の Bean が定義されていない限り、ApplicationContext 内の Bean のバックグラウンド初期化用のブートストラップエグゼキュータ。

ターゲットの配置に応じて、spring.task.execution.mode を force に設定して applicationTaskExecutor を自動構成したり、Executor (標準 Javadoc) AsyncTaskExecutor (Javadoc) に変更したり、カスタム Executor (標準 Javadoc) をラップする AsyncTaskExecutor (Javadoc) AsyncConfigurer (Javadoc) の両方を定義したりすることができます。

force モードが有効になっている場合、@Primary (Javadoc) Bean または Executor (標準 Javadoc) 型の taskExecutor という名前の Bean が存在する場合でも、applicationTaskExecutor は @EnableAsync (Javadoc) とともに通常タスク実行用に設定されます。通常タスク用に Executor をオーバーライドする唯一の方法は、AsyncConfigurer (Javadoc) Bean を登録することです。

ThreadPoolTaskExecutor (Javadoc) が自動構成されると、スレッドプールは負荷に応じて拡大および縮小できる 8 つのコアスレッドを使用します。これらのデフォルト設定は、次の例に示すように、spring.task.execution 名前空間を使用して微調整できます。

  • プロパティ

  • YAML

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

これにより、キューがいっぱい(100 タスク)になったときにスレッドプールが最大 16 スレッドに増加するように、スレッドプールが制限キューを使用するように変更されます。プールの縮小は、スレッドが 10 秒間(デフォルトでは 60 秒ではなく)アイドル状態のときに回収されるため、より積極的です。

スケジュールされたタスクの実行に関連付ける必要がある場合 (たとえば、@EnableScheduling (Javadoc) を使用)、スケジューラを自動構成することもできます。

仮想スレッドが有効になっている場合 (Java 21+ を使用し、spring.threads.virtual.enabled を true に設定)、これは仮想スレッドを使用する SimpleAsyncTaskScheduler (Javadoc) になります。この SimpleAsyncTaskScheduler (Javadoc) は、プール関連のプロパティをすべて無視します。

仮想スレッドが有効になっていない場合は、適切なデフォルトが設定された ThreadPoolTaskScheduler (Javadoc) になります。ThreadPoolTaskScheduler (Javadoc) はデフォルトで 1 つのスレッドを使用し、次の例に示すように、spring.task.scheduling 名前空間を使用して設定を微調整できます。

  • プロパティ

  • YAML

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

カスタムエグゼキュータまたはスケジューラを作成する必要がある場合、コンテキストで ThreadPoolTaskExecutorBuilder (Javadoc) Bean、SimpleAsyncTaskExecutorBuilder (Javadoc) Bean、ThreadPoolTaskSchedulerBuilder (Javadoc) Bean、SimpleAsyncTaskSchedulerBuilder (Javadoc) が使用可能になります。SimpleAsyncTaskExecutorBuilder (Javadoc) および SimpleAsyncTaskSchedulerBuilder (Javadoc) Bean は、仮想スレッドが有効になっている場合 (Java 21+ および spring.threads.virtual.enabled を true に設定して使用)、仮想スレッドを使用するように自動的に構成されます。