ターゲットとなるビジネスサービスの定義
スケジューリングの動作確認を行うために、以下の2つのサービスクラスを準備します。これらは定期的に実行される処理のシミュレーションとして機能します。
package com.example.demo.service;
import org.springframework.stereotype.Service;
@Service
public class PaymentProcessingService {
public void processSettlements() {
System.out.println("決済データのバッチ処理を実行中...");
}
}
package com.example.demo.service;
import org.springframework.stereotype.Service;
@Service
public class LogCleanupService {
public void archiveOldLogs() {
System.out.println("古いログのアーカイブ処理を実行中...");
}
}
Spring標準の@Scheduledアノテーションを使用する方法
最も基本的な方法は、Spring Frameworkが提供するアノテーションベースのスケジューリング機能を利用することです。
まず、メインアプリケーションクラスまたは設定クラスに@EnableSchedulingアノテーションを追加して、スケジューリング機能を有効化する必要があります。
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class TaskSchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(TaskSchedulerApplication.class, args);
}
}
次に、実際に定期実行したい処理を含むコンポーネントを作成します。@Scheduledアノテーションを使用して実行タイミング(Cron式や固定レートなど)を指定します。
package com.example.demo.component;
import com.example.demo.service.LogCleanupService;
import com.example.demo.service.PaymentProcessingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class CoreScheduler {
@Autowired
private PaymentProcessingService paymentService;
@Autowired
private LogCleanupService logService;
// 2秒ごとに実行されるタスク
@Scheduled(cron = "*/2 * * * * ?")
public void runMaintenanceTasks() {
System.out.println(">>> 定期タスクの起動 [CoreScheduler]");
paymentService.processSettlements();
logService.archiveOldLogs();
}
}
Quartzフレームワークの統合
より高度な機能(クラスター管理、ジョブの永続化など)が必要な場合は、Quartzを使用します。spring-boot-starter-quartz依存関係をプロジェクトに追加します。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
Quartzを使用する場合は、QuartzJobBeanを継承したジョブクラスを作成し、executeInternalメソッド内にビジネスロジックを記述します。
package com.example.demo.job;
import com.example.demo.service.LogCleanupService;
import com.example.demo.service.PaymentProcessingService;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class DataSyncJob extends QuartzJobBean {
@Autowired
private PaymentProcessingService paymentService;
@Autowired
private LogCleanupService logService;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
System.out.println(">>> QuartzJobによる同期処理を開始");
paymentService.processSettlements();
logService.archiveOldLogs();
}
}
スケジュールタスクの並列実行設定
デフォルトの@Scheduled設定では、単一のスレッドでタスクが順次実行されるため、あるタスクの処理に時間がかかると、後続のタスクの開始時刻が遅れる(ブロッキングされる)問題が発生します。この問題を解決し、タスクを並列実行させるには、SchedulingConfigurerインターフェースを実装してカスタムのスレッドプールを定義します。
以下の設定では、サイズ5のスケジュール済みスレッドプールを構成することで、複数のタスクが互いの実行時間に影響されずに動作するようにしています。
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executors;
@Configuration
public class CustomSchedulerConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// タスク実行用のスレッドプールをカスタマイズ(ここではスレッド数を5に設定)
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
}
}